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.

2859 lines
80 KiB

  1. #include <windows.h>
  2. #if 0
  3. #include <stdtypes.h>
  4. #endif
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <direct.h>
  8. #include <dos.h>
  9. #include <sys\types.h>
  10. #include <sys\stat.h>
  11. #include <ctype.h> /* isspace */
  12. #include <io.h>
  13. #include <limits.h> /* UINT_MAX */
  14. #include <memory.h> /* _fmemcpy, _fmemccpy */
  15. #include <lzexpand.h>
  16. #include <shellapi.h> /* HKEY, HKEY_CLASSES_ROOT, ERROR_SUCCESS */
  17. #include "setup.h"
  18. #include "genthk.h" /* thunks for calls to get 32-bit version */
  19. #include "driveex.h"
  20. #include <stdtypes.h>
  21. /* Messages for optional background task.
  22. */
  23. #define IDM_ACME_STARTING 261
  24. #define IDM_ACME_COMPLETE 262
  25. #define IDM_ACME_FAILURE 263
  26. #ifdef APPCOMP
  27. #include <decomp.h>
  28. #endif /* APPCOMP */
  29. #include <fdi.h>
  30. /* List file extension */
  31. char szLstExt[] = "LST";
  32. /* List file section names */
  33. char szDefaultParamsSect[] = "Params";
  34. char szDefaultFilesSect[] = "Files";
  35. char szWin3xParamsSect[] = "Win3.x Params";
  36. char szWin3xFilesSect[] = "Win3.x Files";
  37. char szWin95ParamsSect[] = "Windows 95 Params";
  38. char szWin95FilesSect[] = "Windows 95 Files";
  39. char szNTAlphaParamsSect[] = "NT Alpha Params";
  40. char szNTAlphaFilesSect[] = "NT Alpha Files";
  41. char szNTMipsParamsSect[] = "NT Mips Params";
  42. char szNTMipsFilesSect[] = "NT Mips Files";
  43. char szNTPpcParamsSect[] = "NT PPC Params";
  44. char szNTPpcFilesSect[] = "NT PPC Files";
  45. char szNTIntelParamsSect[] = "NT Intel Params";
  46. char szNTIntelFilesSect[] = "NT Intel Files";
  47. char szNTVerIntelParamsSect[] = "NT3.51 Intel Params";
  48. char szNTVerIntelFilesSect[] = "NT3.51 Intel Files";
  49. char * szParamsSect = szNull;
  50. char * szFilesSect = szNull;
  51. typedef struct _PLATFORM_SPEC
  52. {
  53. BYTE minMajorVersion;
  54. BYTE minMinorVersion;
  55. char *szParamsSect;
  56. char *szFilesSect;
  57. } PLATFORM_SPEC, *PPLATFORM_SPEC;
  58. PLATFORM_SPEC aIntelSpec[] =
  59. {
  60. {3, 51, szNTVerIntelParamsSect, szNTVerIntelFilesSect},
  61. {0, 0, szNTIntelParamsSect, szNTIntelFilesSect},
  62. {0, 0, NULL, NULL}
  63. };
  64. PLATFORM_SPEC aAlphaSpec[] =
  65. {
  66. {0, 0, szNTAlphaParamsSect, szNTAlphaFilesSect},
  67. {3, 51, szNTVerIntelParamsSect, szNTVerIntelFilesSect},
  68. {0, 0, szNTIntelParamsSect, szNTIntelFilesSect},
  69. {0, 0, NULL, NULL}
  70. };
  71. PLATFORM_SPEC aMipsSpec[] =
  72. {
  73. {0, 0, szNTMipsParamsSect, szNTMipsFilesSect},
  74. {0, 0, NULL, NULL}
  75. };
  76. PLATFORM_SPEC aPpcSpec[] =
  77. {
  78. {0, 0, szNTPpcParamsSect, szNTPpcFilesSect},
  79. {0, 0, NULL, NULL}
  80. };
  81. PLATFORM_SPEC aEmptySpec[] =
  82. {
  83. {0, 0, NULL, NULL}
  84. };
  85. // Note: this is indexed by PROCESSOR_ARCHITECTURE_xxx
  86. // definitions in ntexapi.h
  87. //
  88. // Note: may want to add extra sections for IA64 and AXP64
  89. PPLATFORM_SPEC aaPlatformSpecs[] =
  90. {
  91. aIntelSpec, // PROCESSOR_ARCHITECTURE_INTEL 0
  92. aMipsSpec, // PROCESSOR_ARCHITECTURE_MIPS 1
  93. aAlphaSpec, // PROCESSOR_ARCHITECTURE_ALPHA 2
  94. aPpcSpec, // PROCESSOR_ARCHITECTURE_PPC 3
  95. aEmptySpec, // PROCESSOR_ARCHITECTURE_SHX 4
  96. aEmptySpec, // PROCESSOR_ARCHITECTURE_ARM 5
  97. aIntelSpec, // PROCESSOR_ARCHITECTURE_IA64 6
  98. aAlphaSpec, // PROCESSOR_ARCHITECTURE_ALPHA64 7
  99. };
  100. /* CPU environment variable and values */
  101. /* (NOTE: These must be upper case) */
  102. char szCpuEnvVarName[] = "PROCESSOR_ARCHITECTURE";
  103. char szIntelEnvVarVal[] = "X86";
  104. char szIA64EnvVarVal[] = "IA64";
  105. char szAlphaEnvVarVal[] = "ALPHA";
  106. char szAXP64EnvVarVal[] = "AXP64";
  107. char szMipsEnvVarVal[] = "MIPS";
  108. char szPpcEnvVarVal[] = "PPC";
  109. /* Bootstrapper class name */
  110. char szBootClass[] = "STUFF-BOOT";
  111. /* String buffer sizes */
  112. #define cchLstLineMax 128
  113. #define cchWinExecLineMax (256 + cchFullPathMax)
  114. /* No. of retries to attempt when removing files or dirs,
  115. * or when executing a chmod.
  116. */
  117. #define cRetryMax 1200
  118. /* SetErrorMode flags */
  119. #define fNoErrMes 1
  120. #define fErrMes 0
  121. /* Quiet Mode -- Note: EEL must be kept in sync with acmsetup.h */
  122. typedef UINT EEL; /* Exit Error Level */
  123. #define eelSuccess ((EEL)0x0000)
  124. #define eelBootstrapperFailed ((EEL)0x0009) /* Used only in Bootstrapper! */
  125. EEL eelExitErrorLevel = eelBootstrapperFailed;
  126. BOOL fQuietMode = fFalse;
  127. BOOL fExeced = fFalse;
  128. BOOL fWin31 = fFalse;
  129. /* Forward Declarations */
  130. VOID CleanUpTempDir ( char *, char * );
  131. BRC BrcInstallFiles ( char *, char *, char * );
  132. BOOL FCreateTempDir ( char *, char * );
  133. BRC BrcCopyFiles ( char *, char *, char * );
  134. VOID RemoveFiles ( char * );
  135. BRC BrcCopy ( char *, char * );
  136. LONG LcbFreeDrive ( int );
  137. BOOL FVirCheck ( HANDLE );
  138. HWND HwndInitBootWnd ( HANDLE );
  139. LRESULT CALLBACK BootWndProc ( HWND, UINT, WPARAM, LPARAM );
  140. BOOL FGetFileSize ( char *, UINT * );
  141. BRC BrcBuildFileLists ( char *, UINT );
  142. VOID FreeFileLists ( VOID );
  143. BOOL FExecAndWait ( char *, HWND );
  144. BOOL FWriteBatFile ( OFSTRUCT, char *, char * );
  145. BOOL FLstSectionExists ( char * szLstFileName, char * szSect );
  146. DWORD GetCpuArchitecture();
  147. BOOL FNotifyAcme ( VOID );
  148. BOOL FGetAcmeErrorLevel ( EEL * peel );
  149. BOOL FCreateRegKey ( CSZC cszcKey );
  150. BOOL FDoesRegKeyExist ( CSZC cszcKey );
  151. BOOL FCreateRegKeyValue ( CSZC cszcKey, CSZC cszcValue );
  152. BOOL FGetRegKeyValue ( CSZC cszcKey, SZ szBuf, CB cbBufMax );
  153. VOID DeleteRegKey ( CSZC cszcKey );
  154. BOOL FFlushRegKey ( VOID );
  155. BOOL FWriteToRestartFile ( SZ szTmpDir );
  156. BOOL FCreateIniFileName ( SZ szIniFile, CB cbBufMax );
  157. BOOL FReadIniFile ( SZ szIniFile, HLOCAL * phlocal, PCB pcbBuf );
  158. BOOL FAllocNewBuf ( CB cbOld, SZ szTmpDir, SZ szSection, SZ szKey,
  159. HLOCAL * phlocal, PCB pcbToBuf );
  160. BOOL FProcessFile ( HLOCAL hlocalFrom, HLOCAL hlocalTo, CB cbToBuf,
  161. SZ szTmpDir, SZ szSection, SZ szKey );
  162. VOID CopyIniLine ( SZ szKey, SZ szTmpDir, SZ szFile, PSZ pszToBuf );
  163. BOOL FWriteIniFile ( SZ szIniFile, HLOCAL hlocalTo );
  164. BRC BrcInsertDisk(CHAR *pchStf, CHAR *pchSrcDrive);
  165. BOOL FRenameBadMaintStf ( SZ szStf );
  166. /* Bootstrapper list file params */
  167. char rgchSetupDirName[cchLstLineMax];
  168. #ifdef UNUSED /* Replaced by DrvWinClass */
  169. char rgchDrvModName[cchLstLineMax];
  170. #endif /* UNUSED */
  171. char rgchDrvWinClass[cchLstLineMax];
  172. char rgchCmdLine[cchLstLineMax];
  173. char rgchBootTitle[cchLstLineMax];
  174. char rgchBootMess[cchLstLineMax];
  175. char rgchWin31Mess[cchLstLineMax];
  176. char rgchCabinetFName[cchLstLineMax];
  177. char rgchBackgroundFName[cchLstLineMax];
  178. char rgchBkgWinClass[cchLstLineMax];
  179. char rgchInsertCDMsg[cchLstLineMax];
  180. char rgchInsertDiskMsg[cchLstLineMax];
  181. LONG lcbDiskFreeMin;
  182. int cFirstCabinetNum;
  183. int cLastCabinetNum;
  184. HANDLE hSrcLst = NULL;
  185. HANDLE hDstLst = NULL;
  186. char rgchErrorFile[cchFullPathMax];
  187. HANDLE hinstBoot = NULL;
  188. HWND hwndBoot = NULL;
  189. CHAR rgchInsufMem[cchSzMax] = "";
  190. CHAR rgchInitErr[cchSzMax] = "";
  191. CHAR rgchSetup[cchSzMax] = "";
  192. /*
  193. ** 'Fixup' temp dir string by removing any subdirs and ensuring
  194. ** extension is only one character. (Note - Win3.0 has bug with
  195. ** WinExec'ing some EXEs from a full 8.3 directory!)
  196. **************************************************************************/
  197. void FixupTempDirName( LPSTR szDir )
  198. {
  199. LPSTR szNext;
  200. int cch = 0;
  201. if (*szDir == '\\'
  202. || *(AnsiNext(szDir)) == ':')
  203. {
  204. lstrcpy(szDir, "~msstfqf.t");
  205. return;
  206. }
  207. while (*szDir != '\\'
  208. && *szDir != '.'
  209. && *szDir != '\0'
  210. && *szDir != ':'
  211. && cch++ < 8)
  212. {
  213. szDir = AnsiNext(szDir);
  214. }
  215. szNext = AnsiNext(szDir);
  216. if (*szDir == '.'
  217. && *szNext != '.'
  218. && *szNext != '\\'
  219. && *szNext != '\0'
  220. && *szNext != ':')
  221. {
  222. *(AnsiNext(szNext)) = '\0';
  223. return;
  224. }
  225. *szDir = '\0';
  226. lstrcat(szDir, ".t");
  227. }
  228. /* Displays bootstrapper messages.
  229. * If fError is true, it's an error message, otherwise it's
  230. * just a message (e.g. insert disk 1).
  231. **************************************************************************/
  232. int DispErrBrc ( BRC brc, BOOL fError, UINT fuStyle,
  233. const char *sz1, const char *sz2,
  234. const char *sz3 )
  235. {
  236. char rgchTitle[256];
  237. char rgchMessage[256];
  238. char szBuf[256 + cchFullPathMax + 256];
  239. #ifndef DEBUG
  240. if (fQuietMode)
  241. {
  242. return (IDCANCEL);
  243. }
  244. #endif
  245. if (LoadString(hinstBoot, brcGen, rgchTitle, 256) == 0
  246. || LoadString(hinstBoot, brc, rgchMessage, 256) == 0)
  247. {
  248. MessageBox(hwndBoot, rgchInsufMem, rgchInitErr, MB_OK | MB_ICONSTOP);
  249. return 0;
  250. }
  251. if (!fError)
  252. lstrcpy(rgchTitle, rgchSetup);
  253. if (sz1 == NULL) sz1 = "";
  254. if (sz2 == NULL) sz2 = "";
  255. if (sz3 == NULL) sz3 = "";
  256. if (brc == brcFile)
  257. wsprintf(szBuf, rgchMessage, (LPSTR)AnsiUpper(rgchErrorFile));
  258. else if (brc == brcDS || brc == brcMemDS)
  259. wsprintf(szBuf, rgchMessage, lcbDiskFreeMin / 1024L);
  260. else
  261. wsprintf(szBuf, rgchMessage, sz1, sz2, sz3);
  262. if ((brc == brcMemDS || brc == brcNoSpill)
  263. && LoadString(hinstBoot, brcMemDSHlp, rgchMessage, 256))
  264. {
  265. lstrcat(szBuf, rgchMessage);
  266. }
  267. else if (brc == brcConnectToSource
  268. && LoadString(hinstBoot, brcConnectHlp, rgchMessage, 256))
  269. {
  270. lstrcat(szBuf, rgchMessage);
  271. }
  272. return (MessageBox(hwndBoot, szBuf, rgchTitle, fuStyle));
  273. }
  274. /*
  275. ** Purpose:
  276. ** Installs Setup executable in a temporary directory on an
  277. ** available hardrive, and launches Setup. After Setup
  278. ** completes, removes the temporary files and directory.
  279. ** Arguments:
  280. ** Standard Windows WinMain args.
  281. ** Returns:
  282. ** Returns eelExitErrorLevel. 0 == Success.
  283. **************************************************************************/
  284. int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
  285. LPSTR lpszCmdParam, int nCmdShow )
  286. {
  287. char chDrive;
  288. char rgchDstDir[cchFullPathMax] = " :\\"; // WARN: kept as OEM chars
  289. char * szDstDirSlash = szNull;
  290. char rgchModuleFileName[cchFullPathMax]; // WARN: kept as ANSI chars
  291. char rgchLstFileName[cchFullPathMax];
  292. char rgchTemp[cchFullPathMax];
  293. char rgchSrcDir[cchFullPathMax];
  294. UINT cbLstSize;
  295. char rgchWinExecLine[cchWinExecLineMax];
  296. UINT uiRes;
  297. int iModLen;
  298. BRC brc;
  299. BOOL fCleanupTemp = FALSE;
  300. LPSTR sz;
  301. HWND hWndBkg = 0; /* window of background task */
  302. UINT hMod;
  303. Unused(nCmdShow);
  304. hinstBoot = hInstance;
  305. rgchErrorFile[0] = '\0';
  306. if (LoadString(hinstBoot, IDS_InsufMem, rgchInsufMem,
  307. sizeof rgchInsufMem) == 0
  308. || LoadString(hinstBoot, IDS_InitErr, rgchInitErr,
  309. sizeof rgchInitErr) == 0
  310. || LoadString(hinstBoot, IDS_Setup, rgchSetup,
  311. sizeof rgchSetup) == 0)
  312. {
  313. /* REVIEW: If these LoadStrngs fail, the user will never know...
  314. * But we can't hard-code strings in an .h file because INTL
  315. * requires all localizable strings to be in resources!
  316. */
  317. #ifdef DEBUG
  318. MessageBox(NULL, "Initial LoadString's failed; probably out of memory.",
  319. szDebugMsg, MB_OK | MB_ICONEXCLAMATION);
  320. #endif /* DEBUG */
  321. }
  322. for (sz = lpszCmdParam; *sz != '\0'; sz = AnsiNext(sz))
  323. {
  324. if ((*sz == '-' || *sz == '/')
  325. && toupper(*(sz+1)) == 'Q' && toupper(*(sz+2)) == 'T')
  326. {
  327. fQuietMode = fTrue;
  328. break;
  329. }
  330. }
  331. /*
  332. * REVIEW: Check that this code is still functional before restoring it.
  333. */
  334. #if VIRCHECK
  335. if (!FVirCheck(hInstance))
  336. {
  337. DispErrBrc(brcVir, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  338. goto LCleanupAndExit;
  339. }
  340. #endif
  341. if (hPrevInstance || FindWindow(szBootClass, NULL) != NULL)
  342. {
  343. DispErrBrc(brcInst, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  344. goto LCleanupAndExit;
  345. }
  346. GetModuleFileName(hInstance, rgchModuleFileName, cchFullPathMax);
  347. /*
  348. * If the first switch on the command line is /M, then it specifies
  349. * the real module name to use.
  350. */
  351. if ((lpszCmdParam[0] == '-' || lpszCmdParam[0] == '/')
  352. && toupper(lpszCmdParam[1]) == 'M')
  353. {
  354. char *pCh, *pCh2;
  355. BOOL fQuotedFileName;
  356. /* Skip the spaces */
  357. for (pCh = lpszCmdParam+2; *pCh == ' '; pCh++);
  358. fQuotedFileName = (*pCh == '\"');
  359. if (fQuotedFileName)
  360. {
  361. pCh++;
  362. }
  363. /* Copy the file name, and add the EOS */
  364. lstrcpy(rgchModuleFileName, pCh);
  365. for (pCh2=rgchModuleFileName;
  366. (*pCh2 != ' ' || fQuotedFileName) &&
  367. (*pCh2 != '\"' || !fQuotedFileName) &&
  368. *pCh2 != '\0';
  369. pCh2++);
  370. *pCh2 = '\0';
  371. /* Remove the /M param from the command line */
  372. lpszCmdParam = pCh + lstrlen(rgchModuleFileName);
  373. if (fQuotedFileName && *lpszCmdParam == '\"')
  374. {
  375. lpszCmdParam++;
  376. }
  377. /* Remove trailing whitespace from the command line */
  378. for (pCh = lpszCmdParam; *pCh == ' '; pCh++);
  379. lpszCmdParam = pCh;
  380. }
  381. OemToAnsi(rgchModuleFileName, rgchModuleFileName);
  382. // Windows 3.0 bug with UNC paths - prepends windows drive letter
  383. sz = (LPSTR)rgchModuleFileName;
  384. if (*sz != '\0'
  385. && *sz != '\\'
  386. && *(sz = AnsiNext(sz)) == ':'
  387. && *(sz = AnsiNext(sz)) == '\\'
  388. && *AnsiNext(sz) == '\\')
  389. {
  390. LPSTR szDst = (LPSTR)rgchModuleFileName;
  391. while ((*szDst++ = *sz++) != '\0')
  392. ;
  393. }
  394. iModLen = lstrlen(rgchModuleFileName);
  395. lstrcpy(rgchSrcDir, rgchModuleFileName);
  396. sz = (LPSTR)&rgchSrcDir[iModLen];
  397. while (sz > (LPSTR)rgchSrcDir && *sz != '\\')
  398. sz = AnsiPrev(rgchSrcDir, sz);
  399. Assert(sz > (LPSTR)rgchSrcDir);
  400. *(AnsiNext(sz)) = '\0';
  401. /*
  402. * If the first switch on the command line is /L, then it specifies
  403. * the name of the .lst file to use.
  404. */
  405. rgchTemp[0] = '\0';
  406. if ((lpszCmdParam[0] == '-' || lpszCmdParam[0] == '/')
  407. && toupper(lpszCmdParam[1]) == 'L')
  408. {
  409. char *pCh, *pCh2;
  410. /* Skip the spaces */
  411. for (pCh = lpszCmdParam+2; *pCh == ' ' && *pCh != '\0'; pCh++);
  412. /* Copy the .lst file name, and add the newline */
  413. lstrcpy(rgchTemp, pCh);
  414. for (pCh2=rgchTemp; *pCh2 != ' ' && *pCh2!= '\0'; pCh2++);
  415. *pCh2 = '\0';
  416. /* Remove the /L param from the command line */
  417. lpszCmdParam = pCh + lstrlen(rgchTemp);
  418. for (pCh = lpszCmdParam; *pCh == ' ' && *pCh != '\0'; pCh++);
  419. lpszCmdParam = pCh;
  420. }
  421. /* If there is something on the command line, use it as the .lst file */
  422. if (*rgchTemp != '\0')
  423. {
  424. lstrcpy(rgchLstFileName, rgchSrcDir);
  425. lstrcat(rgchLstFileName, rgchTemp);
  426. }
  427. else
  428. {
  429. lstrcpy(rgchLstFileName, rgchModuleFileName);
  430. sz = (LPSTR)&rgchLstFileName[iModLen];
  431. while (sz > (LPSTR)rgchLstFileName && *sz != '.')
  432. sz = AnsiPrev(rgchLstFileName, sz);
  433. Assert(sz > (LPSTR)rgchLstFileName);
  434. *(AnsiNext(sz)) = '\0';
  435. lstrcat(rgchLstFileName, szLstExt);
  436. }
  437. if (!FGetFileSize(rgchLstFileName, &cbLstSize) || cbLstSize == 0)
  438. {
  439. lstrcpy(rgchErrorFile, rgchLstFileName);
  440. DispErrBrc(brcFile, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  441. goto LCleanupAndExit;
  442. }
  443. #ifndef WF_WINNT
  444. #define WF_WINNT 0x4000
  445. #endif
  446. /* Attempt to use appropriate platform.
  447. */
  448. szParamsSect = szNull;
  449. szFilesSect = szNull;
  450. if (1)
  451. {
  452. DWORD dwVers = 0;
  453. DWORD dwCpuArchitecture;
  454. DWORD dwMajorVersion;
  455. DWORD dwMinorVersion;
  456. PPLATFORM_SPEC pPlatformSpec;
  457. dwCpuArchitecture = GetCpuArchitecture();
  458. dwVers = GetVersion();
  459. dwMajorVersion = LOBYTE(LOWORD(dwVers));
  460. dwMinorVersion = HIBYTE(LOWORD(dwVers));
  461. if (dwCpuArchitecture < (sizeof (aaPlatformSpecs) / sizeof(aaPlatformSpecs[0])))
  462. {
  463. pPlatformSpec = aaPlatformSpecs[dwCpuArchitecture];
  464. }
  465. else
  466. {
  467. pPlatformSpec = aEmptySpec;
  468. }
  469. for (; pPlatformSpec->szParamsSect != NULL; pPlatformSpec++)
  470. {
  471. if (((pPlatformSpec->minMajorVersion < dwMajorVersion) ||
  472. (pPlatformSpec->minMajorVersion == dwMajorVersion && pPlatformSpec->minMinorVersion <= dwMinorVersion)) &&
  473. FLstSectionExists(rgchLstFileName, pPlatformSpec->szParamsSect))
  474. {
  475. szParamsSect = pPlatformSpec->szParamsSect;
  476. szFilesSect = pPlatformSpec->szFilesSect;
  477. break;
  478. }
  479. }
  480. }
  481. else /* non-WinNT */
  482. {
  483. if (FLstSectionExists(rgchLstFileName, szWin95ParamsSect)
  484. && (LOBYTE(LOWORD(GetVersion())) > 3
  485. || HIBYTE(LOWORD(GetVersion())) >= 95))
  486. {
  487. szParamsSect = szWin95ParamsSect;
  488. szFilesSect = szWin95FilesSect;
  489. }
  490. else
  491. {
  492. fWin31 = fTrue;
  493. if (FLstSectionExists(rgchLstFileName, szWin3xParamsSect))
  494. {
  495. szParamsSect = szWin3xParamsSect;
  496. szFilesSect = szWin3xFilesSect;
  497. }
  498. }
  499. }
  500. if (szParamsSect == szNull)
  501. {
  502. if (FLstSectionExists(rgchLstFileName, szDefaultParamsSect))
  503. {
  504. szParamsSect = szDefaultParamsSect;
  505. szFilesSect = szDefaultFilesSect;
  506. }
  507. else
  508. {
  509. DispErrBrc(brcNoCpuSect, TRUE, MB_OK | MB_ICONSTOP, NULL,
  510. NULL, NULL);
  511. goto LCleanupAndExit;
  512. }
  513. }
  514. if (GetPrivateProfileString(szParamsSect, "TmpDirName", "",
  515. rgchSetupDirName, cchLstLineMax, rgchLstFileName) <= 0
  516. || (lcbDiskFreeMin = GetPrivateProfileInt(szParamsSect,
  517. "TmpDirSize", 0, rgchLstFileName) * 1024L) <= 0
  518. || (cFirstCabinetNum = GetPrivateProfileInt(szParamsSect,
  519. "FirstCabNum", 1, rgchLstFileName)) <= 0
  520. || (cLastCabinetNum = GetPrivateProfileInt(szParamsSect,
  521. "LastCabNum", 1, rgchLstFileName)) <= 0
  522. #ifdef UNUSED
  523. || GetPrivateProfileString(szParamsSect, "DrvModName", "",
  524. rgchDrvModName, cchLstLineMax, rgchLstFileName) <= 0
  525. #endif /* UNUSED */
  526. || GetPrivateProfileString(szParamsSect, "DrvWinClass", "",
  527. rgchDrvWinClass, cchLstLineMax, rgchLstFileName) <= 0
  528. || GetPrivateProfileString(szParamsSect, "CmdLine", "", rgchCmdLine,
  529. cchLstLineMax, rgchLstFileName) <= 0
  530. //|| GetPrivateProfileString(szParamsSect, "Require31", "",
  531. // rgchWin31Mess, cchLstLineMax, rgchLstFileName) <= 0
  532. || GetPrivateProfileString(szParamsSect, "WndTitle", "",
  533. rgchBootTitle, cchLstLineMax, rgchLstFileName) <= 0
  534. || GetPrivateProfileString(szParamsSect, "WndMess", "",
  535. rgchBootMess, cchLstLineMax, rgchLstFileName) <= 0)
  536. {
  537. DispErrBrc(brcLst, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  538. goto LCleanupAndExit;
  539. }
  540. if (FindWindow(rgchDrvWinClass, NULL) != NULL)
  541. {
  542. DispErrBrc(brcInst, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  543. goto LCleanupAndExit;
  544. }
  545. GetPrivateProfileString(szParamsSect, "CabinetFile", "",
  546. rgchCabinetFName, cchLstLineMax, rgchLstFileName);
  547. GetPrivateProfileString(szParamsSect, "InsertCDMsg", "",
  548. rgchInsertCDMsg, cchLstLineMax, rgchLstFileName);
  549. GetPrivateProfileString(szParamsSect, "InsertDiskMsg", "",
  550. rgchInsertDiskMsg, cchLstLineMax, rgchLstFileName);
  551. if (rgchWin31Mess[0] != '\0'
  552. && LOBYTE(LOWORD((DWORD)GetVersion())) == 3
  553. && HIBYTE(LOWORD((DWORD)GetVersion())) < 10)
  554. {
  555. if (!fQuietMode)
  556. {
  557. char rgchTitle[256];
  558. if (LoadString(hinstBoot, brcGen, rgchTitle, 256) == 0)
  559. lstrcpy(rgchTitle, rgchSetup);
  560. MessageBox(hwndBoot, rgchWin31Mess, rgchTitle,
  561. MB_OK | MB_ICONSTOP);
  562. }
  563. goto LCleanupAndExit;
  564. }
  565. FixupTempDirName(rgchSetupDirName);
  566. for (sz = rgchBootMess; *sz != '\0'; sz = AnsiNext(sz))
  567. if (*sz == '\\' && *(sz+1) == 'n')
  568. {
  569. *sz++ = '\r';
  570. *sz = '\n';
  571. }
  572. /* If there is a /W then is specifies we are in add/remove mode with
  573. the setup app not installed. We need to read it off CD/Floppy/Network
  574. */
  575. if ((lpszCmdParam[0] == '-' || lpszCmdParam[0] == '/')
  576. && toupper(lpszCmdParam[1]) == 'W')
  577. {
  578. CHAR rgchStf[_MAX_PATH];
  579. char *pCh, *pCh2, *pCh3;
  580. /* Skip the spaces */
  581. for (pCh = lpszCmdParam+2; *pCh == ' ' && *pCh != '\0'; pCh++);
  582. lstrcpy(rgchStf, rgchSrcDir);
  583. pCh3 = rgchStf + lstrlen(rgchStf);
  584. /* Copy the .stf file name, and add the newline */
  585. for (pCh2=pCh; *pCh2 != ' ' && *pCh2!= '\0'; pCh2++)
  586. *pCh3++ = *pCh2;
  587. *pCh3 = '\0';
  588. /* Remove the /W parameter */
  589. lpszCmdParam = pCh2;
  590. /* Get them to insert the correct disk */
  591. if ((brc = BrcInsertDisk(rgchStf, rgchSrcDir)) != brcOkay)
  592. {
  593. if (brc != brcMax)
  594. DispErrBrc(brc, TRUE, MB_OK | MB_ICONSTOP, rgchStf, NULL, NULL);
  595. goto LCleanupAndExit;
  596. }
  597. }
  598. GetPrivateProfileString(szParamsSect, "Background", "",
  599. rgchBackgroundFName, cchLstLineMax, rgchLstFileName);
  600. GetPrivateProfileString(szParamsSect, "BkgWinClass", "",
  601. rgchBkgWinClass, cchLstLineMax, rgchLstFileName);
  602. if (rgchBackgroundFName[0] != '\0')
  603. {
  604. lstrcpy(rgchTemp, rgchSrcDir);
  605. lstrcat(rgchTemp, rgchBackgroundFName);
  606. if (rgchBkgWinClass[0] != '\0')
  607. {
  608. lstrcat(rgchTemp, " /C");
  609. lstrcat(rgchTemp, rgchBkgWinClass);
  610. }
  611. lstrcat(rgchTemp, " /T");
  612. lstrcat(rgchTemp, rgchBootTitle);
  613. lstrcat(rgchTemp, " /M");
  614. lstrcat(rgchTemp, rgchBootMess);
  615. hMod = WinExec(rgchTemp, SW_SHOWNORMAL); /* ignore if exec failed */
  616. #ifdef DEBUG
  617. if (hMod < 32)
  618. {
  619. wsprintf(szDebugBuf, "%s: Background WinExec failed.",
  620. rgchBackgroundFName);
  621. MessageBox(NULL, szDebugBuf, szDebugMsg, MB_OK | MB_ICONSTOP);
  622. }
  623. #endif /* DEBUG */
  624. hWndBkg = FindWindow(rgchBkgWinClass, rgchBootTitle);
  625. }
  626. if (!hWndBkg && (hwndBoot = HwndInitBootWnd(hInstance)) == NULL)
  627. {
  628. DispErrBrc(brcMem, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  629. goto LCleanupAndExit;
  630. }
  631. if ((brc = BrcBuildFileLists(rgchLstFileName, cbLstSize)) != brcOkay)
  632. {
  633. DispErrBrc(brc, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  634. goto LCleanupAndExit;
  635. }
  636. lstrcat(rgchDstDir, "~MSSETUP.T");
  637. szDstDirSlash = rgchDstDir + lstrlen(rgchDstDir);
  638. lstrcat(rgchDstDir, "\\");
  639. lstrcat(rgchDstDir, rgchSetupDirName);
  640. AnsiToOem(rgchDstDir, rgchDstDir);
  641. for (chDrive = 'Z'; chDrive >= 'A'; --chDrive)
  642. {
  643. UINT fModeSav;
  644. BOOL fDriveFixed;
  645. fModeSav = SetErrorMode(fNoErrMes);
  646. fDriveFixed = (GetDriveTypeEx(chDrive - 'A') == EX_DRIVE_FIXED);
  647. SetErrorMode(fModeSav);
  648. if (fDriveFixed)
  649. {
  650. *rgchDstDir = chDrive;
  651. brc = BrcInstallFiles(rgchSrcDir, rgchDstDir, szDstDirSlash);
  652. if (brc == brcOkay)
  653. break;
  654. if (brc == brcFile)
  655. {
  656. DispErrBrc(brc, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  657. goto LCleanupAndExit;
  658. }
  659. else if (brc == brcNoSpill)
  660. {
  661. /* Message already handled in HfOpenSpillFile */
  662. goto LCleanupAndExit;
  663. }
  664. }
  665. }
  666. if (chDrive < 'A')
  667. {
  668. uiRes = GetWindowsDirectory(rgchDstDir, cchFullPathMax);
  669. Assert(uiRes > 0);
  670. #if DBCS // [J1] Fixed DBCS raid #46.
  671. AnsiUpper(rgchDstDir);
  672. #endif
  673. /* BLOCK */
  674. {
  675. LPSTR sz = (LPSTR)&rgchDstDir[uiRes];
  676. sz = AnsiPrev(rgchDstDir, sz);
  677. if (*sz != '\\')
  678. lstrcat(rgchDstDir, "\\");
  679. }
  680. lstrcat(rgchDstDir, "~MSSETUP.T");
  681. szDstDirSlash = rgchDstDir + lstrlen(rgchDstDir);
  682. lstrcat(rgchDstDir, "\\");
  683. Assert(lstrlen(rgchDstDir) + lstrlen(rgchSetupDirName)
  684. < cchFullPathMax);
  685. lstrcat(rgchDstDir, rgchSetupDirName);
  686. AnsiToOem(rgchDstDir, rgchDstDir);
  687. brc = BrcInstallFiles(rgchSrcDir, rgchDstDir, szDstDirSlash);
  688. if (brc != brcOkay)
  689. {
  690. /* NoSpill message already handled in HfOpenSpillFile */
  691. if (brc != brcNoSpill)
  692. {
  693. DispErrBrc(brc, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  694. }
  695. goto LCleanupAndExit;
  696. }
  697. }
  698. hSrcLst = LocalFree(hSrcLst); /* don't need src list anymore */
  699. Assert(hSrcLst == NULL);
  700. /* Use full path to .exe; don't rely on cwd (fails under Win95).
  701. */
  702. /* block */
  703. {
  704. char rgchTmp[cchWinExecLineMax];
  705. wsprintf(rgchTmp, rgchCmdLine, (LPSTR)rgchSrcDir,
  706. lpszCmdParam);
  707. Assert(lstrlen(rgchTmp) + lstrlen(rgchDstDir) + 1 < cchWinExecLineMax);
  708. lstrcpy(rgchWinExecLine, rgchDstDir);
  709. lstrcat(rgchWinExecLine, "\\");
  710. lstrcat(rgchWinExecLine, rgchTmp);
  711. }
  712. GlobalCompact((DWORD)(64L * 1024L));
  713. fCleanupTemp = TRUE;
  714. if (!fWin31 && !FNotifyAcme())
  715. {
  716. #if DEBUG
  717. DispErrBrc(brcRegDb, TRUE, MB_OK | MB_ICONEXCLAMATION, NULL, NULL, NULL);
  718. #endif /* DEBUG */
  719. /* Try running Acme anyway. */
  720. }
  721. if (!fWin31 && !FWriteToRestartFile(rgchDstDir))
  722. {
  723. #ifdef DEBUG
  724. MessageBox(NULL, "Write to restart file failed. Setup can continue, "
  725. "but some initialization files might not get removed "
  726. "if Setup must restart Windows.",
  727. szDebugMsg, MB_OK | MB_ICONEXCLAMATION);
  728. #endif /* DEBUG */
  729. /*
  730. * Any errors encountered will have been displayed where they occured.
  731. * Try running Acme anyway.
  732. */
  733. }
  734. if (hWndBkg)
  735. SendMessage(hWndBkg, WM_COMMAND, IDM_ACME_STARTING, 0);
  736. if (!FExecAndWait(rgchWinExecLine, hwndBoot))
  737. {
  738. DispErrBrc(brcMem, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  739. goto LCleanupAndExit;
  740. }
  741. fExeced = fTrue;
  742. LCleanupAndExit:
  743. if (fCleanupTemp && szDstDirSlash != szNull)
  744. CleanUpTempDir(rgchDstDir, szDstDirSlash);
  745. FreeFileLists();
  746. eelExitErrorLevel = eelBootstrapperFailed;
  747. if (fExeced && !FGetAcmeErrorLevel(&eelExitErrorLevel))
  748. {
  749. #ifdef UNUSED
  750. /* NOTE: Removed to avoid the message on WinNT. On NT, Acme can
  751. * exit and the bootstrapper can kick in before the restart
  752. * actually happens, causing this message (since Acme has already
  753. * removed the reg key as part of its reboot cleanup). We'll
  754. * leave the eelFailed value, though, since no one should be
  755. * relying on it at reboot anyway, and it may help catch other
  756. * problems down the road.
  757. */
  758. DispErrBrc(brcRegDb, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  759. #endif /* UNUSED */
  760. Assert(eelExitErrorLevel == eelBootstrapperFailed);
  761. }
  762. if (hwndBoot != NULL)
  763. DestroyWindow(hwndBoot);
  764. if (hWndBkg && IsWindow(hWndBkg))
  765. {
  766. SendMessage(hWndBkg, WM_COMMAND, eelExitErrorLevel == eelSuccess ?
  767. IDM_ACME_COMPLETE : IDM_ACME_FAILURE, 0);
  768. if (IsWindow(hWndBkg))
  769. PostMessage(hWndBkg, WM_QUIT, 0, 0);
  770. }
  771. return (eelExitErrorLevel);
  772. }
  773. /*
  774. ** Purpose:
  775. ** Creates and temporary subdirectory at the given path,
  776. ** appends it to the given path, and copies the Setup files
  777. ** into it.
  778. ** Arguments:
  779. ** szModule: Full path to bootstrapper's directory (ANSI chars).
  780. ** rgchDstDir: Full path to destination directory (OEM chars).
  781. ** Returns:
  782. ** One of the following Bootstrapper return codes:
  783. ** brcMem out of memory
  784. ** brcDS out of disk space
  785. ** brcMemDS out of memory or disk space
  786. ** brcFile expected source file missing
  787. ** brcOkay completed without error
  788. **************************************************************************/
  789. BRC BrcInstallFiles ( char * szModule, char * rgchDstDir,
  790. char * szDstDirSlash )
  791. {
  792. BRC brc;
  793. if (LcbFreeDrive(*rgchDstDir - 'A' + 1) < lcbDiskFreeMin)
  794. return (brcDS);
  795. if (!FCreateTempDir(rgchDstDir, szDstDirSlash))
  796. return (brcMemDS);
  797. if ((brc = BrcCopyFiles(szModule, rgchDstDir, szDstDirSlash)) != brcOkay)
  798. {
  799. CleanUpTempDir(rgchDstDir, szDstDirSlash);
  800. return (brc);
  801. }
  802. SetFileAttributes(rgchDstDir, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
  803. Assert(szDstDirSlash);
  804. Assert(*szDstDirSlash == '\\');
  805. *szDstDirSlash = '\0';
  806. SetFileAttributes(rgchDstDir, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
  807. *szDstDirSlash = '\\';
  808. return (brcOkay);
  809. }
  810. /*
  811. ** Purpose:
  812. ** Removes the temporary files and directory.
  813. ** Arguments:
  814. ** rgchDstDir: Full path to temp directory (OEM chars).
  815. ** Returns:
  816. ** None.
  817. **************************************************************************/
  818. VOID CleanUpTempDir ( char * rgchDstDir, char * szDstDirSlash )
  819. {
  820. char rgchRoot[] = " :\\";
  821. int i;
  822. RemoveFiles(rgchDstDir);
  823. rgchRoot[0] = *rgchDstDir;
  824. _chdir(rgchRoot);
  825. SetFileAttributes(rgchDstDir, FILE_ATTRIBUTE_NORMAL);
  826. /* Try to remove the directory up to cRetryMax times.
  827. */
  828. for (i = 0; i < cRetryMax; i++)
  829. {
  830. if (_rmdir(rgchDstDir) == 0)
  831. break;
  832. }
  833. Assert(szDstDirSlash);
  834. Assert(*szDstDirSlash == '\\');
  835. *szDstDirSlash = '\0';
  836. SetFileAttributes(rgchDstDir, FILE_ATTRIBUTE_NORMAL);
  837. /* Try to remove the directory up to cRetryMax times.
  838. */
  839. for (i = 0; i < cRetryMax; i++)
  840. {
  841. if (_rmdir(rgchDstDir) == 0)
  842. break;
  843. }
  844. *szDstDirSlash = '\\';
  845. }
  846. /*
  847. ** Purpose:
  848. ** Creates a temporary subdirectory at the given path,
  849. ** and appends it to the given path.
  850. ** Arguments:
  851. ** rgchDir: Full path to destination directory (OEM chars).
  852. ** Returns:
  853. ** TRUE if directory was successfully created,
  854. ** FALSE if not.
  855. **************************************************************************/
  856. BOOL FCreateTempDir ( char * rgchDir, char * szDstDirSlash )
  857. {
  858. char rgchTmp[cchFullPathMax];
  859. FILE * fp;
  860. char * pch;
  861. int fErr;
  862. int i = 0;
  863. pch = (char *)(&rgchDir[lstrlen(rgchDir)]);
  864. Assert(*pch == '\0');
  865. _chdrive(*rgchDir - 'A' + 1);
  866. Assert(szDstDirSlash);
  867. Assert(*szDstDirSlash == '\\');
  868. *szDstDirSlash = '\0';
  869. _mkdir(rgchDir);
  870. *szDstDirSlash = '\\';
  871. while (!_access(rgchDir, 0))
  872. {
  873. if (!_chdir(rgchDir))
  874. {
  875. /* verify dir is write-able */
  876. lstrcpy(rgchTmp, rgchDir);
  877. lstrcat(rgchTmp, "\\tXXXXXX");
  878. Assert(lstrlen(rgchTmp) < cchFullPathMax);
  879. if (_mktemp(rgchTmp) != NULL
  880. && (fp = fopen(rgchTmp, "w")) != NULL)
  881. {
  882. fErr = fclose(fp);
  883. Assert(!fErr);
  884. fErr = remove(rgchTmp);
  885. #ifdef DBCS // [J2] Fixed DBCS raid #28.
  886. if (fErr) // Keep the directory name
  887. *pch = '\0';
  888. #else
  889. *pch = '\0';
  890. #endif
  891. return (!fErr);
  892. }
  893. }
  894. if (++i > 9)
  895. break;
  896. _itoa(i, pch, 10);
  897. Assert(lstrlen(rgchDir) < cchFullPathMax);
  898. }
  899. if (i <= 9 && !_mkdir(rgchDir))
  900. {
  901. fErr = _chdir(rgchDir);
  902. Assert(!fErr);
  903. #ifdef DBCS // [J2] Fixed DBCS raid #28.
  904. // Keep the directory name
  905. #else
  906. *pch = '\0';
  907. #endif
  908. return (TRUE);
  909. }
  910. *pch = '\0';
  911. return (FALSE);
  912. }
  913. /*
  914. ** Purpose:
  915. ** Reopens BAT file and writes DEL or RMDIR line.
  916. ** Arguments:
  917. ** of: OFSTRUCT to REOPEN.
  918. ** szCmd: Command (ANSI chars). ["DEL" or "RMDIR"]
  919. ** szArg: Fully qualified pathname for argument (OEM chars).
  920. ** Returns:
  921. ** TRUE or FALSE.
  922. **************************************************************************/
  923. BOOL FWriteBatFile ( OFSTRUCT of, char * szCmd, char * szArg )
  924. {
  925. int fhBat = -1;
  926. BOOL fRet = TRUE;
  927. if ((fhBat = OpenFile("a", &of, OF_REOPEN | OF_WRITE)) == -1
  928. || _llseek(fhBat, 0L, 2) == -1L
  929. || _lwrite(fhBat, szCmd, lstrlen(szCmd)) != (UINT)lstrlen(szCmd)
  930. || _lwrite(fhBat, (LPSTR)" ", 1) != 1
  931. || _lwrite(fhBat, szArg, lstrlen(szArg)) != (UINT)lstrlen(szArg)
  932. || _lwrite(fhBat, (LPSTR)"\r\n", 2) != 2)
  933. {
  934. fRet = FALSE;
  935. }
  936. if (fhBat != -1)
  937. {
  938. int fErr = _lclose(fhBat);
  939. Assert(fErr != -1);
  940. }
  941. return (fRet);
  942. }
  943. #ifdef DEBUG
  944. /*
  945. ** Purpose:
  946. ** Checks if destination filename is a valid 8.3 name with no path
  947. */
  948. BOOL FValidFATFileName ( char* szName )
  949. {
  950. int iLen, ch;
  951. for (iLen = 0; (ch = *szName++) != '\0'; iLen++)
  952. {
  953. if (ch <= ' ' || ch == '\\' || ch == ':' || ch == ',')
  954. return fFalse;
  955. if (ch == '.')
  956. {
  957. if (iLen == 0 || iLen > 8)
  958. return fFalse;
  959. iLen = 9;
  960. }
  961. if (iLen == 8 || iLen == 13)
  962. return fFalse;
  963. }
  964. return (iLen > 0);
  965. }
  966. #endif /* DEBUG */
  967. /*
  968. ** Purpose:
  969. ** Copies the source files into the given destination dir.
  970. ** Arguments:
  971. ** szModule: Source path (ANSI chars).
  972. ** szDstDir: Destination path (OEM chars).
  973. ** Returns:
  974. ** One of the following bootstrapper return codes:
  975. ** brcMem out of memory
  976. ** brcDS out of disk space
  977. ** brcMemDS out of memory or disk space
  978. ** brcFile expected source file missing
  979. ** brcOkay completed without error
  980. **************************************************************************/
  981. BRC BrcCopyFiles ( char * szModule, char * szDstDir, char * szDstDirSlash )
  982. {
  983. char rgchSrcFullPath[cchFullPathMax];
  984. char rgchDstFullPath[cchFullPathMax];
  985. char rgchTmpDirPath[cchFullPathMax];
  986. char * szSrc;
  987. char * szDst;
  988. int cbSrc;
  989. BRC brc = brcOkay;
  990. int fhBat = -1;
  991. OFSTRUCT ofBat;
  992. int fErr;
  993. BOOL fCabinetFiles = FALSE;
  994. lstrcpy(rgchDstFullPath, szDstDir);
  995. lstrcat(rgchDstFullPath, "\\_MSSETUP._Q_");
  996. Assert(lstrlen(rgchDstFullPath) < cchFullPathMax);
  997. _chmod(rgchDstFullPath, S_IREAD | S_IWRITE);
  998. remove(rgchDstFullPath);
  999. OemToAnsi(rgchDstFullPath, rgchDstFullPath);
  1000. fhBat = OpenFile(rgchDstFullPath, &ofBat, OF_CREATE | OF_WRITE);
  1001. AnsiToOem(rgchDstFullPath, rgchDstFullPath);
  1002. if (fhBat == -1)
  1003. return (brcMemDS);
  1004. fErr = _lclose(fhBat);
  1005. Assert(!fErr);
  1006. szSrc = (char *)LocalLock(hSrcLst);
  1007. if (szSrc == NULL)
  1008. return (brcMem);
  1009. szDst = (char *)LocalLock(hDstLst);
  1010. if (szDst == NULL) {
  1011. LocalUnlock (hSrcLst);
  1012. return (brcMem);
  1013. }
  1014. for (;
  1015. (cbSrc = lstrlen(szSrc)) != 0;
  1016. szSrc += cbSrc + 1, szDst += lstrlen(szDst) + 1)
  1017. {
  1018. //
  1019. // This code has been added so that we can detect a path
  1020. // in setup.lst for the right hand side of the equals sign. This
  1021. // allows us flexiblity in specifying where files like setup.inf
  1022. // should be pulled from, otherwise we always use the files from
  1023. // the original source location. If we detect "<anything>:\" or
  1024. // "\\" then we assume it is a path.
  1025. //
  1026. if( ((':' == szSrc[1]) && ('\\' == szSrc[2])) ||
  1027. (('\\' == szSrc[0]) && ('\\' == szSrc[1])) )
  1028. {
  1029. rgchSrcFullPath[0] = '\0';
  1030. }
  1031. else
  1032. {
  1033. lstrcpy(rgchSrcFullPath, szModule);
  1034. }
  1035. lstrcat(rgchSrcFullPath, szSrc);
  1036. lstrcpy(rgchDstFullPath, szDstDir);
  1037. lstrcat(rgchDstFullPath, "\\");
  1038. lstrcat(rgchDstFullPath, szDst);
  1039. #ifdef DEBUG
  1040. if (!FValidFATFileName(szDst))
  1041. {
  1042. wsprintf(szDebugBuf, "Invalid destination file, must be 8.3: %s",
  1043. szDst);
  1044. MessageBox(NULL, szDebugBuf, szDebugMsg, MB_OK | MB_ICONSTOP);
  1045. continue;
  1046. }
  1047. #endif /* DEBUG */
  1048. Assert(lstrlen(rgchSrcFullPath) < cchFullPathMax);
  1049. Assert(lstrlen(rgchDstFullPath) < cchFullPathMax);
  1050. if ( !FWriteBatFile(ofBat, "ATTRIB -R", rgchDstFullPath)
  1051. || !FWriteBatFile(ofBat, "DEL", rgchDstFullPath))
  1052. {
  1053. brc = brcDS;
  1054. break;
  1055. }
  1056. if (*szSrc == '@') /* cabinet file */
  1057. {
  1058. if (*rgchCabinetFName == '\0')
  1059. {
  1060. brc = brcFile;
  1061. #ifdef DEBUG
  1062. lstrcpy(rgchErrorFile, ". Missing CABINET= line");
  1063. #endif //DEBUG
  1064. break;
  1065. }
  1066. fCabinetFiles = TRUE;
  1067. continue;
  1068. }
  1069. if ((brc = BrcCopy(rgchSrcFullPath, rgchDstFullPath)) != brcOkay)
  1070. break;
  1071. _chmod(rgchDstFullPath, S_IREAD);
  1072. }
  1073. LocalUnlock(hSrcLst);
  1074. LocalUnlock(hDstLst);
  1075. lstrcpy(rgchDstFullPath, szDstDir);
  1076. lstrcat(rgchDstFullPath, "\\_MSSETUP._Q_");
  1077. Assert(lstrlen(rgchDstFullPath) < cchFullPathMax);
  1078. Assert(szDstDirSlash != szNull);
  1079. Assert(*szDstDirSlash == chDirSep);
  1080. *szDstDirSlash = chEos;
  1081. lstrcpy(rgchTmpDirPath, szDstDir);
  1082. *szDstDirSlash = chDirSep;
  1083. if (brc == brcOkay
  1084. && (!FWriteBatFile(ofBat, "DEL", rgchDstFullPath)
  1085. || !FWriteBatFile(ofBat, "RMDIR", szDstDir)
  1086. || !FWriteBatFile(ofBat, "RMDIR", rgchTmpDirPath)))
  1087. {
  1088. return (brcDS);
  1089. }
  1090. if (fCabinetFiles && brc == brcOkay)
  1091. {
  1092. szSrc = (char *)LocalLock(hSrcLst);
  1093. if(szSrc == NULL)
  1094. return (brcMem);
  1095. szDst = (char *)LocalLock(hDstLst);
  1096. if( szDst == NULL) {
  1097. LocalUnlock (hSrcLst);
  1098. return (brcMem);
  1099. }
  1100. #ifdef DEBUG
  1101. if (!FValidFATFileName(rgchCabinetFName))
  1102. {
  1103. wsprintf(szDebugBuf, "Invalid cabinet file, must be 8.3: %s",
  1104. rgchCabinetFName);
  1105. MessageBox(NULL, szDebugBuf, szDebugMsg, MB_OK | MB_ICONSTOP);
  1106. }
  1107. else
  1108. #endif /* DEBUG */
  1109. brc = BrcHandleCabinetFiles(hwndBoot, rgchCabinetFName,
  1110. cFirstCabinetNum, cLastCabinetNum, szModule, szDstDir,
  1111. szSrc, szDst, rgchErrorFile, rgchDstFullPath);
  1112. LocalUnlock(hSrcLst);
  1113. LocalUnlock(hDstLst);
  1114. }
  1115. return (brc);
  1116. }
  1117. /*
  1118. ** Purpose:
  1119. ** Removes the files previously copied to the temp dest dir.
  1120. ** Arguments:
  1121. ** szDstDir: full path to destination directory (OEM chars).
  1122. ** Returns:
  1123. ** None.
  1124. **************************************************************************/
  1125. VOID RemoveFiles ( char * szDstDir )
  1126. {
  1127. char rgchDstFullPath[cchFullPathMax];
  1128. char * szDst;
  1129. int cbDst;
  1130. int i;
  1131. OFSTRUCT ofs;
  1132. UINT fModeSav;
  1133. fModeSav = SetErrorMode(fNoErrMes);
  1134. szDst = (char *)LocalLock(hDstLst);
  1135. if (szDst == NULL)
  1136. return;
  1137. for (; (cbDst = lstrlen(szDst)) != 0; szDst += cbDst + 1)
  1138. {
  1139. lstrcpy(rgchDstFullPath, szDstDir);
  1140. lstrcat(rgchDstFullPath, "\\");
  1141. lstrcat(rgchDstFullPath, szDst);
  1142. Assert(lstrlen(rgchDstFullPath) < cchFullPathMax);
  1143. /* Don't try to remove the file if it doesn't exist */
  1144. if (OpenFile(rgchDstFullPath, &ofs, OF_EXIST) == HFILE_ERROR)
  1145. continue;
  1146. /* Try to _chmod the file up to cRetryMax times.
  1147. */
  1148. for (i = 0; i < cRetryMax; i++)
  1149. {
  1150. if (_chmod(rgchDstFullPath, S_IWRITE) == 0)
  1151. break;
  1152. FYield();
  1153. }
  1154. /* Try to remove the file up to cRetryMax times.
  1155. */
  1156. for (i = 0; i < cRetryMax; i++)
  1157. {
  1158. if (remove(rgchDstFullPath) == 0)
  1159. break;
  1160. FYield();
  1161. }
  1162. }
  1163. LocalUnlock(hDstLst);
  1164. SetErrorMode(fModeSav);
  1165. lstrcpy(rgchDstFullPath, szDstDir);
  1166. lstrcat(rgchDstFullPath, "\\_MSSETUP._Q_");
  1167. Assert(lstrlen(rgchDstFullPath) < cchFullPathMax);
  1168. _chmod(rgchDstFullPath, S_IWRITE);
  1169. remove(rgchDstFullPath);
  1170. }
  1171. /*
  1172. ** Purpose:
  1173. ** Copies the given source file to the given destination.
  1174. ** Arguments:
  1175. ** szFullPathSrc: full path name of source file (ANSI chars).
  1176. ** szFullPathDst: full path name of destination file (OEM chars).
  1177. ** Returns:
  1178. ** One of the following bootstrapper return codes:
  1179. ** brcMem out of memory
  1180. ** brcDS out of disk space
  1181. ** brcMemDS out of memory or disk space
  1182. ** brcFile expected source file missing
  1183. ** brcOkay completed without error
  1184. **************************************************************************/
  1185. BRC BrcCopy ( char * szFullPathSrc, char * szFullPathDst )
  1186. {
  1187. int fhSrc = -1;
  1188. int fhDst = -1;
  1189. OFSTRUCT ofSrc, ofDst;
  1190. BRC brc = brcMemDS;
  1191. int fErr;
  1192. #ifdef APPCOMP
  1193. if ((fhSrc = OpenFile(szFullPathSrc, &ofSrc, OF_READ)) == -1)
  1194. {
  1195. brc = brcFile;
  1196. lstrcpy(rgchErrorFile, szFullPathSrc);
  1197. goto CopyFailed;
  1198. }
  1199. #endif /* APPCOMP */
  1200. /* REVIEW: BUG: if szFullPathDst is an existing subdirectory
  1201. ** instead of a file, we'll fail trying to open it, think we're
  1202. ** out of disk space, and go back up to try another disk.
  1203. ** This is acceptable for now.
  1204. */
  1205. _chmod(szFullPathDst, S_IREAD | S_IWRITE);
  1206. OemToAnsi(szFullPathDst, szFullPathDst);
  1207. fhDst = OpenFile(szFullPathDst, &ofDst, OF_CREATE | OF_WRITE);
  1208. AnsiToOem(szFullPathDst, szFullPathDst);
  1209. if (fhDst == -1)
  1210. goto CopyFailed;
  1211. #ifdef APPCOMP
  1212. if (WReadHeaderInfo(fhSrc) > 0)
  1213. {
  1214. LONG lRet;
  1215. lRet = LcbDecompFile(fhSrc, fhDst, -1, 0, TRUE, NULL, 0L, NULL, 0,
  1216. NULL);
  1217. if (lRet < 0L)
  1218. {
  1219. if (lRet == (LONG)rcOutOfMemory)
  1220. brc = brcMem;
  1221. if (lRet == (LONG)rcWriteError)
  1222. brc = brcDS;
  1223. goto CopyFailed;
  1224. }
  1225. FFreeHeaderInfo();
  1226. }
  1227. else /* copy the file using LZExpand */
  1228. #endif /* APPCOMP */
  1229. {
  1230. HFILE hSrcLZ;
  1231. DWORD dwRet;
  1232. #ifdef APPCOMP
  1233. fErr = _lclose(fhSrc);
  1234. Assert(!fErr);
  1235. fhSrc = -1;
  1236. #endif /* APPCOMP */
  1237. if ((hSrcLZ = LZOpenFile(szFullPathSrc, &ofSrc, OF_READ)) == -1)
  1238. {
  1239. brc = brcFile;
  1240. lstrcpy(rgchErrorFile, szFullPathSrc);
  1241. goto CopyFailed;
  1242. }
  1243. /* We would like to yield more often, but LZCopy has no callbacks */
  1244. FYield();
  1245. dwRet = LZCopy(hSrcLZ, fhDst);
  1246. LZClose(hSrcLZ);
  1247. if (dwRet >= LZERROR_UNKNOWNALG)
  1248. {
  1249. if (dwRet == LZERROR_GLOBALLOC)
  1250. brc = brcMem;
  1251. if (dwRet == LZERROR_WRITE)
  1252. brc = brcDS;
  1253. goto CopyFailed;
  1254. }
  1255. }
  1256. brc = brcOkay;
  1257. CopyFailed:
  1258. #ifdef APPCOMP
  1259. if (fhSrc != -1)
  1260. {
  1261. fErr = _lclose(fhSrc);
  1262. Assert(!fErr);
  1263. }
  1264. #endif /* APPCOMP */
  1265. if (fhDst != -1)
  1266. {
  1267. fErr = _lclose(fhDst);
  1268. Assert(!fErr);
  1269. }
  1270. return (brc);
  1271. }
  1272. /*
  1273. ** Purpose:
  1274. ** Determine the storage space remaining on disk.
  1275. ** Arguments:
  1276. ** nDrive: drive number (1='A', 2='B', etc.)
  1277. ** Returns:
  1278. ** Number of bytes free on disk,
  1279. ** or 0 if not a valid drive.
  1280. +++
  1281. ** Implementation:
  1282. ** Calls DOS interrupt 21h, funct 36h.
  1283. **************************************************************************/
  1284. LONG LcbFreeDrive ( int nDrive )
  1285. {
  1286. LONG lcbRet;
  1287. CHAR achRoot[4];
  1288. ULARGE_INTEGER freeBytes;
  1289. achRoot[0] = 'A'+nDrive-1;
  1290. achRoot[1] = ':';
  1291. achRoot[2] = '\\';
  1292. achRoot[3] = 0;
  1293. memset(&freeBytes, 0, sizeof(freeBytes));
  1294. GetDiskFreeSpaceEx(achRoot, &freeBytes, 0, 0);
  1295. lcbRet = freeBytes.LowPart;
  1296. /* KLUDGE: Drives bigger than 2 GB can return zero total space!
  1297. */
  1298. if (lcbRet < 0L || lcbRet > (999999L * 1024L))
  1299. {
  1300. return (999999L * 1024L);
  1301. }
  1302. return (lcbRet);
  1303. }
  1304. /*
  1305. ** Purpose:
  1306. ** Creates and displays bootstrapper window.
  1307. ** Arguments:
  1308. ** hInstance: process instance handle
  1309. ** Returns:
  1310. ** Window handle to bootstrapper window, or
  1311. ** NULL if the window could not be created.
  1312. **************************************************************************/
  1313. HWND HwndInitBootWnd ( HANDLE hInstance )
  1314. {
  1315. WNDCLASS wc;
  1316. HWND hwnd;
  1317. int cx, cy;
  1318. wc.style = 0;
  1319. wc.lpfnWndProc = BootWndProc;
  1320. wc.cbClsExtra = 0;
  1321. wc.cbWndExtra = 0;
  1322. wc.hInstance = hInstance;
  1323. wc.hIcon = NULL;
  1324. wc.hCursor = NULL;
  1325. wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  1326. wc.lpszMenuName = NULL;
  1327. wc.lpszClassName = szBootClass;
  1328. if (!RegisterClass(&wc))
  1329. return (NULL);
  1330. cx = GetSystemMetrics(SM_CXSCREEN) / 2;
  1331. cy = GetSystemMetrics(SM_CYSCREEN) / 3;
  1332. hwnd = CreateWindow(szBootClass, rgchBootTitle,
  1333. WS_DLGFRAME, cx / 2, cy, cx, cy, NULL, NULL, hInstance, NULL);
  1334. if (hwnd == NULL)
  1335. return (NULL);
  1336. if (!fQuietMode)
  1337. {
  1338. ShowWindow(hwnd, SW_SHOWNORMAL);
  1339. UpdateWindow(hwnd);
  1340. }
  1341. return (hwnd);
  1342. }
  1343. // ripped off from mvdm\wow32\wgtext.c
  1344. ULONG GetTextExtent(HDC hdc, LPSTR lpstr, int cbString)
  1345. {
  1346. ULONG ul = 0;
  1347. SIZE size4;
  1348. if ((GetTextExtentPoint(
  1349. hdc,
  1350. lpstr,
  1351. cbString,
  1352. &size4
  1353. )))
  1354. {
  1355. // check if either cx or cy are bigger than SHRT_MAX == 7fff
  1356. // but do it in ONE SINGLE check
  1357. if ((size4.cx | size4.cy) & ~SHRT_MAX)
  1358. {
  1359. if (size4.cx > SHRT_MAX)
  1360. ul = SHRT_MAX;
  1361. else
  1362. ul = (ULONG)size4.cx;
  1363. if (size4.cy > SHRT_MAX)
  1364. ul |= (SHRT_MAX << 16);
  1365. else
  1366. ul |= (ULONG)(size4.cy << 16);
  1367. }
  1368. else
  1369. {
  1370. ul = (ULONG)(size4.cx | (size4.cy << 16));
  1371. }
  1372. }
  1373. return (ul);
  1374. }
  1375. /*
  1376. ** Purpose:
  1377. ** WndProc for bootstrapper window.
  1378. ** Arguments:
  1379. ** Standard Windows WndProc arguments.
  1380. ** Returns:
  1381. ** Result of call DefWindowProc, or zero if WM_PAINT message.
  1382. **************************************************************************/
  1383. LRESULT CALLBACK BootWndProc ( HWND hwnd, UINT wMsgID, WPARAM wParam,
  1384. LPARAM lParam )
  1385. {
  1386. HDC hdc;
  1387. PAINTSTRUCT ps;
  1388. RECT rect;
  1389. UINT iMargin;
  1390. switch (wMsgID)
  1391. {
  1392. #ifdef DBCS // [J3] Fixed KK raid #12.
  1393. case WM_CREATE:
  1394. {
  1395. if (!fQuietMode)
  1396. {
  1397. int x, y, cx, cy;
  1398. hdc = BeginPaint(hwnd, &ps);
  1399. GetClientRect(hwnd, &rect);
  1400. cx = (LOWORD(GetTextExtent(hdc, rgchBootMess, lstrlen(rgchBootMess))) + 13) / 14 * 16 + 2;
  1401. if (cx > rect.right)
  1402. {
  1403. if (cx > GetSystemMetrics(SM_CXSCREEN))
  1404. cx = GetSystemMetrics(SM_CXSCREEN);
  1405. x = (GetSystemMetrics(SM_CXSCREEN) - cx) / 2;
  1406. y = cy = GetSystemMetrics(SM_CYSCREEN) / 3;
  1407. SetWindowPos(hwnd, NULL, x, y, cx, cy, SWP_NOZORDER);
  1408. }
  1409. EndPaint(hwnd, &ps);
  1410. }
  1411. break;
  1412. }
  1413. #endif
  1414. case WM_PAINT:
  1415. if (!fQuietMode)
  1416. {
  1417. hdc = BeginPaint(hwnd, &ps);
  1418. GetClientRect(hwnd, &rect);
  1419. iMargin = rect.right / 16;
  1420. rect.top = rect.bottom / 2 - GetSystemMetrics(SM_CYCAPTION);
  1421. rect.left = iMargin;
  1422. rect.right -= iMargin;
  1423. SetBkMode(hdc, TRANSPARENT);
  1424. DrawText(hdc, rgchBootMess, -1, &rect,
  1425. DT_WORDBREAK | DT_CENTER | DT_NOPREFIX);
  1426. EndPaint(hwnd, &ps);
  1427. }
  1428. break;
  1429. default:
  1430. return (DefWindowProc(hwnd, wMsgID, wParam, lParam));
  1431. }
  1432. return (0L);
  1433. }
  1434. /*
  1435. ** Purpose:
  1436. ** Get size of file.
  1437. ** Arguments:
  1438. ** szFile: List file name (full path, ANSI).
  1439. ** pcbSize: Pointer to variable to receive file size.
  1440. ** Returns:
  1441. ** FALSE if file found and size >= 64K.
  1442. ** TRUE otherwise.
  1443. **************************************************************************/
  1444. BOOL FGetFileSize ( char * szFile, UINT * pcbSize )
  1445. {
  1446. int fh;
  1447. int fErr;
  1448. LONG lcb;
  1449. *pcbSize = 0;
  1450. if ((fh = _lopen(szFile, OF_READ)) == -1)
  1451. {
  1452. return (TRUE);
  1453. }
  1454. if ((lcb = _llseek(fh, 0L, 2)) > 65535)
  1455. {
  1456. #pragma warning(disable:4127) /* conditional expression is constant */
  1457. Assert(FALSE);
  1458. #pragma warning(default:4127)
  1459. _lclose(fh);
  1460. return (FALSE);
  1461. }
  1462. *pcbSize = (UINT)lcb;
  1463. fErr = _lclose(fh);
  1464. Assert(!fErr);
  1465. return (TRUE);
  1466. }
  1467. /*
  1468. ** Purpose:
  1469. ** Build file Src and Dst lists from LST file.
  1470. ** Arguments:
  1471. ** szFile: List file name (full path, ANSI).
  1472. ** cbFile: Size of list file
  1473. ** Note:
  1474. ** Sets globals: hSrcLst, hDstLst.
  1475. ** Returns:
  1476. ** One of the following Bootstrapper return codes:
  1477. ** brcMem out of memory
  1478. ** brcLst list file is corrupted
  1479. ** brcOkay completed without error
  1480. **************************************************************************/
  1481. BRC BrcBuildFileLists ( char * szFile, UINT cbFile )
  1482. {
  1483. char rgchDst[cchLstLineMax];
  1484. char * szSrc;
  1485. char * szDst;
  1486. char * pchDstStart;
  1487. int cbSrc;
  1488. UINT i;
  1489. /* Build Src List */
  1490. if ((hSrcLst = LocalAlloc(LMEM_MOVEABLE, cbFile)) == NULL)
  1491. return (brcMem);
  1492. szSrc = (char *)LocalLock(hSrcLst);
  1493. if(szSrc == (char *)NULL)
  1494. return (brcMem);
  1495. i = GetPrivateProfileString(szFilesSect, NULL, "", szSrc, cbFile, szFile);
  1496. if (i <= 0)
  1497. {
  1498. LocalUnlock(hSrcLst);
  1499. hSrcLst = LocalFree(hSrcLst);
  1500. Assert(hSrcLst == NULL);
  1501. return (brcLst);
  1502. }
  1503. Assert(i+1 < cbFile);
  1504. szSrc[i++] = '\0'; /* force double zero at end */
  1505. szSrc[i++] = '\0';
  1506. LocalUnlock(hSrcLst);
  1507. hSrcLst = LocalReAlloc(hSrcLst, i, LMEM_MOVEABLE);
  1508. if(hSrcLst == NULL)
  1509. return (brcMem);
  1510. /* Build Dst List */
  1511. if ((hDstLst = LocalAlloc(LMEM_MOVEABLE, cbFile)) == NULL)
  1512. {
  1513. hSrcLst = LocalFree(hSrcLst);
  1514. Assert(hSrcLst == NULL);
  1515. return (brcMem);
  1516. }
  1517. szSrc = (char *)LocalLock(hSrcLst);
  1518. if (szSrc == (char *)NULL)
  1519. return (brcMem);
  1520. szDst = pchDstStart = (char *)LocalLock(hDstLst);
  1521. if (szDst == (char *)NULL) {
  1522. LocalUnlock (hDstLst);
  1523. return (brcMem);
  1524. }
  1525. for (;
  1526. (cbSrc = lstrlen(szSrc)) != 0;
  1527. szSrc += cbSrc + 1, szDst += lstrlen(szDst) + 1)
  1528. {
  1529. if (GetPrivateProfileString(szFilesSect, szSrc, "", rgchDst,
  1530. cchLstLineMax, szFile) <= 0)
  1531. {
  1532. LocalUnlock(hSrcLst);
  1533. LocalUnlock(hDstLst);
  1534. FreeFileLists();
  1535. return (brcLst);
  1536. }
  1537. AnsiToOem(rgchDst, rgchDst);
  1538. lstrcpy(szDst, rgchDst);
  1539. }
  1540. *szDst = '\0'; /* force double zero at end */
  1541. LocalUnlock(hSrcLst);
  1542. LocalUnlock(hDstLst);
  1543. hDstLst = LocalReAlloc(hDstLst, (int)(szDst - pchDstStart) + 1,
  1544. LMEM_MOVEABLE);
  1545. if (hDstLst == NULL)
  1546. return (brcMem);
  1547. return (brcOkay);
  1548. }
  1549. /*
  1550. ** Purpose:
  1551. ** Frees file list buffers with non-NULL handles
  1552. ** and sets them to NULL.
  1553. ** Arguments:
  1554. ** none.
  1555. ** Returns:
  1556. ** none.
  1557. **************************************************************************/
  1558. VOID FreeFileLists ()
  1559. {
  1560. if (hSrcLst != NULL)
  1561. hSrcLst = LocalFree(hSrcLst);
  1562. if (hDstLst != NULL)
  1563. hDstLst = LocalFree(hDstLst);
  1564. Assert(hSrcLst == NULL);
  1565. Assert(hDstLst == NULL);
  1566. }
  1567. /*
  1568. ** Purpose:
  1569. ** Spawns off a process with WinExec and waits for it to complete.
  1570. ** Arguments:
  1571. ** szCmdLn: Line passed to WinExec (cannot have leading spaces).
  1572. ** Returns:
  1573. ** TRUE if successful, FALSE if not.
  1574. +++
  1575. ** Implementation:
  1576. ** GetModuleUsage will RIP under Win 3.0 Debug if module count is
  1577. ** zero (okay to ignore and continue), but the GetModuleHandle
  1578. ** check will catch all zero cases for single instances of the
  1579. ** driver, the usual case. [Under Win 3.1 we will be able to
  1580. ** replace both checks with just an IsTask(hMod) check.]
  1581. **************************************************************************/
  1582. BOOL FExecAndWait ( char * szCmdLn, HWND hwndHide )
  1583. {
  1584. UINT hMod;
  1585. MSG msg;
  1586. Assert(!isspace(*szCmdLn)); /* leading space kills WinExec */
  1587. if ((hMod = WinExec(szCmdLn, SW_SHOWNORMAL)) > 32)
  1588. {
  1589. UINT i;
  1590. UINT_PTR idTimer;
  1591. /* KLUDGE: Give the app some time to create its main window.
  1592. *
  1593. * On newer versions of NT, we were exiting the while loop
  1594. * (below) and cleaning up the temp dir before the app had
  1595. * even put up its window.
  1596. *
  1597. * NOTE: In trials, we only had to retry once, so cRetryMax
  1598. * may be overkill, but it should be pretty rare that this
  1599. * would fail in shipping products anyway.
  1600. */
  1601. for (i = 0; i < cRetryMax; i++)
  1602. {
  1603. if(FindWindow(rgchDrvWinClass, NULL) != NULL)
  1604. break;
  1605. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1606. {
  1607. TranslateMessage(&msg);
  1608. DispatchMessage(&msg);
  1609. }
  1610. }
  1611. /* Set the timer to fire every 1/10 of a second. This is
  1612. necessary because we might never return from GetMessage */
  1613. idTimer = SetTimer(NULL, 0, 100, NULL);
  1614. /*
  1615. ** REVIEW - FindWindow() will wait until the LAST setup quits (not
  1616. ** necessarily this setup. If exec'ing a 16-bit app we could
  1617. ** use the old code:
  1618. ** while (GetModuleHandle(rgchDrvModName) && GetModuleUsage(hMod))
  1619. ** but on NT this fails so for 32-bit apps we could attempt to
  1620. ** remove one of the executable files (slow?).
  1621. **
  1622. ** REVIEW - This loop becomes a busy wait under NT, which is bad.
  1623. ** However, it doesn't appear to affect ACME's performance
  1624. ** noticeably.
  1625. */
  1626. while (FindWindow(rgchDrvWinClass, NULL) != NULL)
  1627. {
  1628. if (GetMessage(&msg, NULL, 0, 0))
  1629. {
  1630. TranslateMessage(&msg);
  1631. DispatchMessage(&msg);
  1632. }
  1633. if (msg.message == WM_TIMER && hwndHide != (HWND)NULL)
  1634. {
  1635. ShowWindow(hwndHide, SW_HIDE);
  1636. hwndHide = (HWND)NULL;
  1637. }
  1638. }
  1639. if (idTimer != 0)
  1640. KillTimer(0, idTimer);
  1641. return (TRUE);
  1642. }
  1643. #ifdef DEBUG
  1644. wsprintf(szDebugBuf, "WinExec Error: %d", hMod);
  1645. MessageBox(NULL, szDebugBuf, szDebugMsg, MB_OK | MB_ICONSTOP);
  1646. #endif /* DEBUG */
  1647. return (FALSE);
  1648. }
  1649. /*
  1650. ** Purpose: Processes messages that may be in the queue.
  1651. ** Arguments: none
  1652. ** Returns: none
  1653. **************************************************************************/
  1654. void PUBLIC FYield ( VOID )
  1655. {
  1656. MSG msg;
  1657. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1658. {
  1659. TranslateMessage(&msg);
  1660. DispatchMessage(&msg);
  1661. }
  1662. }
  1663. /*
  1664. **************************************************************************/
  1665. BOOL FLstSectionExists ( char * szLstFileName, char * szSect )
  1666. {
  1667. return (GetPrivateProfileString(szSect, "CmdLine", "", rgchCmdLine,
  1668. cchLstLineMax, szLstFileName) > 0);
  1669. }
  1670. /*
  1671. **************************************************************************/
  1672. DWORD GetCpuArchitecture ()
  1673. {
  1674. SYSTEM_INFO sysInfo;
  1675. GetSystemInfo(&sysInfo);
  1676. return sysInfo.wProcessorArchitecture;
  1677. }
  1678. static CSZC cszcBootstrapperKey = "MS Setup (ACME)\\Bootstrapper\\Exit Level";
  1679. static CSZC cszcEelRunning = "Running";
  1680. /*
  1681. ** Purpose:
  1682. ** Lets Acme know the bootstrapper launched it. So Acme will let
  1683. ** us know its exit error level.
  1684. ** Arguments:
  1685. ** none.
  1686. ** Returns:
  1687. ** fTrue if successful, fFalse otherwise.
  1688. ** Notes:
  1689. ** REVIEW: Probably should use DDE instead of the Registration
  1690. ** Database.
  1691. **************************************************************************/
  1692. BOOL FNotifyAcme ( VOID )
  1693. {
  1694. if (!FCreateRegKey(cszcBootstrapperKey))
  1695. {
  1696. return (fFalse);
  1697. }
  1698. if (!FCreateRegKeyValue(cszcBootstrapperKey, cszcEelRunning))
  1699. {
  1700. return (fFalse);
  1701. }
  1702. if (!FFlushRegKey())
  1703. {
  1704. return (fFalse);
  1705. }
  1706. return (fTrue);
  1707. }
  1708. /*
  1709. ** Purpose:
  1710. ** Get the exit error level set by Acme and clean up the Registration
  1711. ** Database.
  1712. ** Arguments:
  1713. ** peel: Exit error level (to be set).
  1714. ** Returns:
  1715. ** fTrue if successful, fFalse otherwise.
  1716. **************************************************************************/
  1717. BOOL FGetAcmeErrorLevel ( EEL * peel )
  1718. {
  1719. CHAR rgchValue[cchSzMax];
  1720. if (FGetRegKeyValue(cszcBootstrapperKey, rgchValue, sizeof rgchValue))
  1721. {
  1722. #ifdef DEBUG
  1723. /*
  1724. * Assert(isdigit(rgchValue[0]));
  1725. * Assert(isdigit(rgchValue[1]) || rgchValue[1] == chEos);
  1726. */
  1727. UINT i;
  1728. BOOL fValidValue = fFalse;
  1729. /* Assumes valid values are 1 or 2 digit numbers. */
  1730. for (i = 0; rgchValue[i] != chEos; i++)
  1731. {
  1732. fValidValue = fTrue;
  1733. if (!isdigit(rgchValue[i]) || i > 1)
  1734. {
  1735. fValidValue = fFalse;
  1736. break;
  1737. }
  1738. }
  1739. if (!fValidValue)
  1740. {
  1741. char szBuf[cchSzMax];
  1742. wsprintf(szBuf, "RegKeyValue (%s)", rgchValue);
  1743. MessageBox(NULL, szBuf, "Debug Assertion in FGetAcmeErrorLevel",
  1744. MB_OK | MB_ICONSTOP);
  1745. }
  1746. #endif /* DEBUG */
  1747. *peel = atoi(rgchValue);
  1748. DeleteRegKey(cszcBootstrapperKey);
  1749. return (fTrue);
  1750. }
  1751. else
  1752. {
  1753. if (fWin31)
  1754. {
  1755. *peel = eelSuccess;
  1756. return fTrue;
  1757. }
  1758. return (fFalse);
  1759. }
  1760. }
  1761. /*
  1762. ** Purpose:
  1763. ** Creates a Registration Database key that is a subkey of
  1764. ** cszcBootstrapperKey.
  1765. ****************************************************************************/
  1766. BOOL FCreateRegKey ( CSZC cszcKey )
  1767. {
  1768. HKEY hkey;
  1769. if (RegCreateKey(HKEY_CLASSES_ROOT, cszcKey, &hkey) != ERROR_SUCCESS)
  1770. {
  1771. DispErrBrc(brcRegDb, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  1772. return (fFalse);
  1773. }
  1774. if (RegCloseKey(hkey) != ERROR_SUCCESS)
  1775. {
  1776. DispErrBrc(brcRegDb, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  1777. return (fFalse);
  1778. }
  1779. return (fTrue);
  1780. }
  1781. /*
  1782. ** Purpose:
  1783. ** API to check for the existence of the specified key in
  1784. ** the Registration Database.
  1785. ****************************************************************************/
  1786. BOOL FDoesRegKeyExist ( CSZC cszcKey )
  1787. {
  1788. HKEY hkey;
  1789. if (RegOpenKey(HKEY_CLASSES_ROOT, cszcKey, &hkey) != ERROR_SUCCESS)
  1790. return (fFalse);
  1791. RegCloseKey(hkey);
  1792. return (fTrue);
  1793. }
  1794. /*
  1795. ** Purpose:
  1796. ** Creates a Registration Database key that is a subkey of
  1797. ** HKEY_CLASSES_ROOT and associates a value with the key.
  1798. ****************************************************************************/
  1799. BOOL FCreateRegKeyValue ( CSZC cszcKey, CSZC cszcValue )
  1800. {
  1801. if (RegSetValue(HKEY_CLASSES_ROOT, cszcKey, REG_SZ, cszcValue,
  1802. lstrlen(cszcKey)) != ERROR_SUCCESS)
  1803. {
  1804. DispErrBrc(brcRegDb, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  1805. return (fFalse);
  1806. }
  1807. return (fTrue);
  1808. }
  1809. /*
  1810. ** Purpose:
  1811. ** Determines the value associated with the specified Registration
  1812. ** Database key.
  1813. ****************************************************************************/
  1814. BOOL FGetRegKeyValue ( CSZC cszcKey, SZ szBuf, CB cbBufMax )
  1815. {
  1816. LONG lcb = cbBufMax;
  1817. if (szBuf != szNull && cbBufMax != 0)
  1818. *szBuf = chEos;
  1819. if (!FDoesRegKeyExist(cszcKey))
  1820. return (fFalse);
  1821. if (RegQueryValue(HKEY_CLASSES_ROOT, cszcKey, szBuf, &lcb)
  1822. != ERROR_SUCCESS)
  1823. {
  1824. DispErrBrc(brcRegDb, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  1825. return (fFalse);
  1826. }
  1827. Assert(lcb < cbMaxConst);
  1828. return (fTrue);
  1829. }
  1830. /*
  1831. ** Purpose:
  1832. ** API to remove the specified Registration Database key,
  1833. ** its associated values, and subkeys.
  1834. ****************************************************************************/
  1835. VOID DeleteRegKey ( CSZC cszcKey )
  1836. {
  1837. char rgchKey[cchSzMax], rgchBuffer[cchSzMax];
  1838. char *pch;
  1839. HKEY hKeyT = NULL;
  1840. lstrcpy(rgchKey, cszcKey);
  1841. RegDeleteKey(HKEY_CLASSES_ROOT, rgchKey);
  1842. pch = rgchKey + 1;
  1843. while(pch > rgchKey)
  1844. {
  1845. pch = rgchKey + lstrlen(rgchKey);
  1846. while (pch > rgchKey)
  1847. {
  1848. if (*pch == '\\')
  1849. break;
  1850. pch--;
  1851. }
  1852. if (*pch != '\\')
  1853. break;
  1854. *pch = '\0';
  1855. if (RegOpenKey(HKEY_CLASSES_ROOT, rgchKey, &hKeyT) != ERROR_SUCCESS)
  1856. break;
  1857. if (RegEnumKey(hKeyT, 0, rgchBuffer, sizeof(rgchBuffer)) == ERROR_SUCCESS)
  1858. {
  1859. break;
  1860. }
  1861. RegCloseKey(hKeyT);
  1862. hKeyT = NULL;
  1863. RegDeleteKey(HKEY_CLASSES_ROOT, rgchKey);
  1864. }
  1865. if (hKeyT != NULL)
  1866. RegCloseKey(hKeyT);
  1867. }
  1868. /*
  1869. ** Purpose:
  1870. ** API to flush the specified Registration Database key.
  1871. ****************************************************************************/
  1872. BOOL FFlushRegKey ( VOID )
  1873. {
  1874. /* REVIEW: Does 16 bit code need to flush the RegDb? RegFlushKey is
  1875. 32 bit.
  1876. if (RegFlushKey(HKEY_CLASSES_ROOT)) != ERROR_SUCCESS)
  1877. {
  1878. DispErrBrc(brcRegDb, TRUE, MB_OK | MB_ICONSTOP, NULL, NULL, NULL);
  1879. return (fFalse);
  1880. }
  1881. */
  1882. return (fTrue);
  1883. }
  1884. /*
  1885. ** Purpose:
  1886. ** Write temporary files to restart ini file. So that if Acme reboots,
  1887. ** the files in the temporary directory will be removed. Win95 only.
  1888. ** Arguments:
  1889. ** szTmpDir: Full path to destination directory (OEM chars).
  1890. ** Returns:
  1891. ** fTrue if successful, fFalse otherwise.
  1892. **
  1893. ** REVIEW: The files are removed, but not the temp directories.
  1894. ** There may be a way to do that via the wininit.ini file.
  1895. ** This should be looked into.
  1896. **************************************************************************/
  1897. BOOL FWriteToRestartFile ( SZ szTmpDir )
  1898. {
  1899. char rgchIniFile[_MAX_PATH];
  1900. CB cbFrom;
  1901. CB cbTo;
  1902. HLOCAL hlocalFrom = (HLOCAL)NULL;
  1903. HLOCAL hlocalTo = (HLOCAL)NULL;
  1904. BOOL fRet = fFalse;
  1905. SZ szSection = "rename";
  1906. SZ szKey = "NUL";
  1907. /* This code is not used under NT. */
  1908. if (1)
  1909. {
  1910. return (fTrue);
  1911. }
  1912. if (!FCreateIniFileName(rgchIniFile, sizeof rgchIniFile))
  1913. {
  1914. goto LCleanupAndReturn;
  1915. }
  1916. if (!FGetFileSize(rgchIniFile, &cbFrom))
  1917. {
  1918. goto LCleanupAndReturn;
  1919. }
  1920. if (!FReadIniFile(rgchIniFile, &hlocalFrom, &cbFrom))
  1921. {
  1922. goto LCleanupAndReturn;
  1923. }
  1924. if (!FAllocNewBuf(cbFrom, szTmpDir, szSection, szKey, &hlocalTo, &cbTo))
  1925. {
  1926. goto LCleanupAndReturn;
  1927. }
  1928. if (!FProcessFile(hlocalFrom, hlocalTo, cbTo, szTmpDir, szSection, szKey))
  1929. {
  1930. goto LCleanupAndReturn;
  1931. }
  1932. if (!FWriteIniFile(rgchIniFile, hlocalTo))
  1933. {
  1934. goto LCleanupAndReturn;
  1935. }
  1936. fRet = fTrue;
  1937. LCleanupAndReturn:
  1938. if (hlocalFrom != (HLOCAL)NULL)
  1939. {
  1940. hlocalFrom = LocalFree(hlocalFrom);
  1941. Assert(hlocalFrom == (HLOCAL)NULL);
  1942. }
  1943. if (hlocalTo != (HLOCAL)NULL)
  1944. {
  1945. hlocalTo = LocalFree(hlocalTo);
  1946. Assert(hlocalTo == (HLOCAL)NULL);
  1947. }
  1948. return (fRet);
  1949. }
  1950. /*
  1951. ** Purpose:
  1952. ** Create the restart file name.
  1953. ** Arguments:
  1954. ** szIniFile: Buffer to hold file name.
  1955. ** cbBufMax: Size of buffer.
  1956. ** Returns:
  1957. ** fTrue if successful, fFalse otherwise.
  1958. **************************************************************************/
  1959. BOOL FCreateIniFileName ( SZ szIniFile, CB cbBufMax )
  1960. {
  1961. CB cbWinDir;
  1962. cbWinDir = GetWindowsDirectory((LPSTR)szIniFile, cbBufMax);
  1963. if (cbWinDir == 0)
  1964. {
  1965. #pragma warning(disable:4127) /* conditional expression is constant */
  1966. Assert(fFalse); /* Unusual if this happens. */
  1967. #pragma warning(default:4127)
  1968. return (fFalse);
  1969. }
  1970. Assert(isalpha(*szIniFile));
  1971. Assert(*(szIniFile + 1) == ':');
  1972. if (*(AnsiPrev((LPSTR)szIniFile, (LPSTR)&szIniFile[cbWinDir])) != '\\')
  1973. lstrcat((LPSTR)szIniFile, "\\");
  1974. lstrcat((LPSTR)szIniFile, "wininit.ini");
  1975. Assert((CB)lstrlen(szIniFile) < cbBufMax);
  1976. return (fTrue);
  1977. }
  1978. /*
  1979. ** Purpose:
  1980. ** Read the data from the ini file
  1981. ** Arguments:
  1982. ** szIniFile: Ini file name
  1983. ** phlocal: Pointer to memory handle.
  1984. ** pcbBuf: Pointer to the number of bytes in the buffer.
  1985. ** Returns:
  1986. ** fTrue if successful, fFalse otherwise.
  1987. **************************************************************************/
  1988. BOOL FReadIniFile ( SZ szIniFile, HLOCAL * phlocal, PCB pcbBuf )
  1989. {
  1990. UINT fModeSav;
  1991. HLOCAL hlocal;
  1992. SZ szBuf;
  1993. CB cbBuf;
  1994. BOOL fRet = fFalse;
  1995. Assert(szIniFile != szNull);
  1996. Assert(phlocal != (HLOCAL *)NULL);
  1997. Assert(pcbBuf != pcbNull);
  1998. fModeSav = SetErrorMode(fNoErrMes);
  1999. hlocal = *phlocal;
  2000. cbBuf = *pcbBuf;
  2001. Assert(hlocal == (HLOCAL)NULL);
  2002. if (cbBuf == 0) /* Ini file does not exist or is empty. */
  2003. {
  2004. /* Alloc room for CR, LF, EOS. */
  2005. hlocal = LocalAlloc(LMEM_MOVEABLE, 3);
  2006. if (hlocal == NULL)
  2007. {
  2008. #ifdef DEBUG
  2009. MessageBox(NULL, "Out of memory in FReadIniFile.", szDebugMsg,
  2010. MB_OK | MB_ICONEXCLAMATION);
  2011. #endif /* DEBUG */
  2012. }
  2013. else
  2014. {
  2015. szBuf = (SZ)LocalLock(hlocal);
  2016. if(szBuf == szNull)
  2017. return fFalse;
  2018. *szBuf++ = chCR;
  2019. *szBuf++ = chEol;
  2020. *szBuf = chEos;
  2021. *pcbBuf = 2;
  2022. fRet = fTrue;
  2023. }
  2024. }
  2025. else
  2026. {
  2027. HFILE hfile;
  2028. OFSTRUCT ofs;
  2029. CB cbRead;
  2030. /* Flush cache before calling OpenFile() */
  2031. WritePrivateProfileString(szNull, szNull, szNull, szIniFile);
  2032. hfile = OpenFile(szIniFile, &ofs, OF_READWRITE | OF_SHARE_EXCLUSIVE);
  2033. if (hfile == HFILE_ERROR)
  2034. {
  2035. #ifdef DEBUG
  2036. wsprintf(szDebugBuf, "Can't open file: %s.", szIniFile);
  2037. MessageBox(NULL, szDebugBuf, szDebugMsg,
  2038. MB_OK | MB_ICONEXCLAMATION);
  2039. #endif /* DEBUG */
  2040. goto LCleanupAndReturn;
  2041. }
  2042. hlocal = LocalAlloc(LMEM_MOVEABLE, cbBuf + 1);
  2043. if (hlocal == NULL)
  2044. {
  2045. #ifdef DEBUG
  2046. MessageBox(NULL, "Out of memory in FReadIniFile.", szDebugMsg,
  2047. MB_OK | MB_ICONEXCLAMATION);
  2048. #endif /* DEBUG */
  2049. }
  2050. else
  2051. {
  2052. szBuf = (SZ)LocalLock(hlocal);
  2053. if(szBuf == szNull)
  2054. return fFalse;
  2055. cbRead = (CB)_lread(hfile, szBuf, cbBuf + 1);
  2056. if (cbRead == HFILE_ERROR)
  2057. {
  2058. #ifdef DEBUG
  2059. wsprintf(szDebugBuf, "Can't read file: %s.", szIniFile);
  2060. MessageBox(NULL, szDebugBuf, szDebugMsg,
  2061. MB_OK | MB_ICONEXCLAMATION);
  2062. #endif /* DEBUG */
  2063. }
  2064. else
  2065. {
  2066. Assert(cbRead == cbBuf);
  2067. *(szBuf + cbBuf) = chEos;
  2068. fRet = fTrue;
  2069. }
  2070. }
  2071. hfile = _lclose(hfile);
  2072. Assert(hfile != HFILE_ERROR);
  2073. }
  2074. LCleanupAndReturn:
  2075. if (hlocal != NULL)
  2076. {
  2077. LocalUnlock(hlocal);
  2078. }
  2079. *phlocal = hlocal;
  2080. SetErrorMode(fModeSav);
  2081. return (fRet);
  2082. }
  2083. /*
  2084. ** Purpose:
  2085. ** Allocate buffer for new file.
  2086. ** Arguments:
  2087. ** cbOld: Size of existing file
  2088. ** szTmpDir: Full path to destination directory (OEM chars).
  2089. ** szSection: Ini section name
  2090. ** szKey: Ini key name
  2091. ** phlocal: Pointer to memory handle.
  2092. ** pcbToBuf: Pointer to total size of new buffer.
  2093. ** Returns:
  2094. ** fTrue if successful, fFalse if LocalAlloc failed.
  2095. **************************************************************************/
  2096. BOOL FAllocNewBuf ( CB cbOld, SZ szTmpDir, SZ szSection, SZ szKey,
  2097. HLOCAL * phlocal, PCB pcbToBuf )
  2098. {
  2099. UINT fModeSav;
  2100. SZ szDst;
  2101. CB cbDst;
  2102. CB cbOverhead;
  2103. CB cbNew;
  2104. BOOL fRet = fFalse;
  2105. fModeSav = SetErrorMode(fNoErrMes);
  2106. szDst = (SZ)LocalLock(hDstLst);
  2107. if(szDst == szNull)
  2108. return fFalse;
  2109. /*
  2110. * Added to the old file will be one line per temporary file
  2111. * and (possibly) a section line. cbNew is initialized with
  2112. * the size of the section line, plus enough for the file
  2113. * (_MSSETUP._Q_) which is not in the DstLst.
  2114. *
  2115. * Each line will look like:
  2116. * <szKey>=<szTmpDir>\<szFile><CR><LF>
  2117. */
  2118. cbOverhead = lstrlen(szKey) + 1 + lstrlen(szTmpDir) + 1 + 2;
  2119. cbNew = lstrlen(szSection) + 5 + _MAX_PATH;
  2120. for (; (cbDst = lstrlen(szDst)) != 0; szDst += cbDst + 1)
  2121. {
  2122. cbNew += cbOverhead + cbDst;
  2123. }
  2124. LocalUnlock(hDstLst);
  2125. *pcbToBuf = cbOld + cbNew;
  2126. *phlocal = LocalAlloc(LMEM_MOVEABLE, *pcbToBuf);
  2127. if (*phlocal == NULL)
  2128. {
  2129. #ifdef DEBUG
  2130. MessageBox(NULL, "Out of memory in FAllocNewBuf.", szDebugMsg,
  2131. MB_OK | MB_ICONEXCLAMATION);
  2132. #endif /* DEBUG */
  2133. }
  2134. else
  2135. fRet = fTrue;
  2136. SetErrorMode(fModeSav);
  2137. return (fRet);
  2138. }
  2139. /*
  2140. ** Purpose:
  2141. ** Add the new lines to the ini file.
  2142. ** Arguments:
  2143. ** hlocalFrom: Handle to Src memory.
  2144. ** hlocalTo: Handle to Dst memory.
  2145. ** cbToBuf: Total size of Dst memory.
  2146. ** szTmpDir: Full path to destination directory (OEM chars).
  2147. ** szSection: Ini section name
  2148. ** szKey: Ini key name
  2149. ** Returns:
  2150. ** fTrue if successful, fFalse otherwise.
  2151. **
  2152. ** REVIEW: DBCS writes out different order. See DBCS J6 code and
  2153. ** comments in sysinicm.c.
  2154. **************************************************************************/
  2155. BOOL FProcessFile ( HLOCAL hlocalFrom, HLOCAL hlocalTo, CB cbToBuf,
  2156. SZ szTmpDir, SZ szSection, SZ szKey )
  2157. {
  2158. UINT fModeSav;
  2159. SZ szFromBuf;
  2160. SZ szToBuf;
  2161. SZ szToStart;
  2162. SZ szCur;
  2163. SZ szDst;
  2164. CB cbSect;
  2165. CB cbDst;
  2166. Unused(cbToBuf); /* Used in debug only */
  2167. fModeSav = SetErrorMode(fNoErrMes);
  2168. szFromBuf = (SZ)LocalLock(hlocalFrom);
  2169. if(szFromBuf == szNull)
  2170. return fFalse;
  2171. szToBuf = (SZ)LocalLock(hlocalTo);
  2172. if(szToBuf != szNull) {
  2173. LocalUnlock (hlocalFrom);
  2174. return fFalse;
  2175. }
  2176. szToStart = szToBuf;
  2177. cbSect = lstrlen(szSection);
  2178. for (szCur = szFromBuf; *szCur != chEos; szCur = AnsiNext(szCur))
  2179. {
  2180. if (*szCur == '[' && *((szCur + cbSect + 1)) == ']'
  2181. && _memicmp(szSection, AnsiNext(szCur), cbSect) == 0)
  2182. {
  2183. /* Found section. Copy up to section line. */
  2184. CB cbCopy = (CB)(szCur - szFromBuf);
  2185. memcpy(szToBuf, szFromBuf, cbCopy);
  2186. szToBuf += cbCopy;
  2187. break;
  2188. }
  2189. }
  2190. /* Copy section line. */
  2191. *szToBuf++ = '[';
  2192. memcpy(szToBuf, szSection, cbSect);
  2193. szToBuf += cbSect;
  2194. *szToBuf++ = ']';
  2195. *szToBuf++ = chCR;
  2196. *szToBuf++ = chEol;
  2197. /* Copy new lines. */
  2198. szDst = (SZ)LocalLock(hDstLst);
  2199. if (szDst == szNull) {
  2200. LocalUnlock(hlocalFrom);
  2201. LocalUnlock(hlocalTo);
  2202. return fFalse;
  2203. }
  2204. for (; (cbDst = lstrlen(szDst)) != 0; szDst += cbDst + 1)
  2205. {
  2206. CopyIniLine(szKey, szTmpDir, szDst, &szToBuf);
  2207. }
  2208. LocalUnlock(hDstLst);
  2209. CopyIniLine(szKey, szTmpDir, "_MSSETUP._Q_", &szToBuf);
  2210. /* Copy rest of file. */
  2211. if (*szCur == '[')
  2212. {
  2213. /*
  2214. * Skip section line in From buffer. Allow room for '[', section,
  2215. * ']', CR, LF.
  2216. */
  2217. szCur += cbSect + 4;
  2218. }
  2219. else
  2220. {
  2221. szCur = szFromBuf;
  2222. }
  2223. szToBuf = _memccpy(szToBuf, szCur, chEos, UINT_MAX);
  2224. Assert(szToBuf != szNull);
  2225. Assert((CB)lstrlen(szToStart) < cbToBuf);
  2226. LocalUnlock(hlocalFrom);
  2227. LocalUnlock(hlocalTo);
  2228. SetErrorMode(fModeSav);
  2229. return (fTrue);
  2230. }
  2231. /*
  2232. ** Purpose:
  2233. ** Constructs and copies an ini line to a buffer.
  2234. ** Arguments:
  2235. ** szKey: Ini key name
  2236. ** szTmpDir: Full path to destination directory (OEM chars).
  2237. ** szFile: Name of file in temporary directory.
  2238. ** pszToBuf: Pointer to new buffer.
  2239. ** Returns:
  2240. ** none
  2241. **************************************************************************/
  2242. VOID CopyIniLine ( SZ szKey, SZ szTmpDir, SZ szFile, PSZ pszToBuf )
  2243. {
  2244. char rgchSysIniLine[256];
  2245. CB cbCopy;
  2246. lstrcpy(rgchSysIniLine, szKey);
  2247. lstrcat(rgchSysIniLine, "=");
  2248. lstrcat(rgchSysIniLine, szTmpDir);
  2249. lstrcat(rgchSysIniLine, "\\");
  2250. lstrcat(rgchSysIniLine, szFile);
  2251. Assert(lstrlen(rgchSysIniLine) < sizeof rgchSysIniLine);
  2252. cbCopy = lstrlen(rgchSysIniLine);
  2253. memcpy(*pszToBuf, rgchSysIniLine, cbCopy);
  2254. (*pszToBuf) += cbCopy;
  2255. *(*pszToBuf)++ = chCR;
  2256. *(*pszToBuf)++ = chEol;
  2257. }
  2258. /*
  2259. ** Purpose:
  2260. ** Writes out the new ini file.
  2261. ** Arguments:
  2262. ** szIniFile: Buffer to hold file name.
  2263. ** hlocalTo: Handle to Src memory.
  2264. ** Returns:
  2265. ** fTrue if successful, fFalse otherwise.
  2266. **************************************************************************/
  2267. BOOL FWriteIniFile ( SZ szIniFile, HLOCAL hlocalTo )
  2268. {
  2269. UINT fModeSav;
  2270. SZ szToBuf;
  2271. HFILE hfile;
  2272. OFSTRUCT ofs;
  2273. CB cbWrite;
  2274. BOOL fRet = fFalse;
  2275. fModeSav = SetErrorMode(fNoErrMes);
  2276. szToBuf = (SZ)LocalLock(hlocalTo);
  2277. if(szToBuf == szNull)
  2278. return fFalse;
  2279. hfile = OpenFile(szIniFile, &ofs, OF_CREATE | OF_WRITE);
  2280. if (hfile == HFILE_ERROR)
  2281. {
  2282. #ifdef DEBUG
  2283. wsprintf(szDebugBuf, "Can't open file: %s.", szIniFile);
  2284. MessageBox(NULL, szDebugBuf, szDebugMsg,
  2285. MB_OK | MB_ICONEXCLAMATION);
  2286. #endif /* DEBUG */
  2287. goto LUnlockAndReturn;
  2288. }
  2289. cbWrite = _lwrite(hfile, szToBuf, lstrlen(szToBuf));
  2290. if (cbWrite == HFILE_ERROR)
  2291. {
  2292. #ifdef DEBUG
  2293. wsprintf(szDebugBuf, "Can't write to file: %s.", szIniFile);
  2294. MessageBox(NULL, szDebugBuf, szDebugMsg,
  2295. MB_OK | MB_ICONEXCLAMATION);
  2296. #endif /* DEBUG */
  2297. }
  2298. else
  2299. {
  2300. fRet = fTrue;
  2301. }
  2302. hfile = _lclose(hfile);
  2303. Assert(hfile != HFILE_ERROR);
  2304. LUnlockAndReturn:
  2305. LocalUnlock(hlocalTo);
  2306. SetErrorMode(fModeSav);
  2307. return (fRet);
  2308. }
  2309. CHAR szcStfSrcDir[] = "Source Directory\t";
  2310. #define cchStfSrcDir (sizeof(szcStfSrcDir)-1)
  2311. /* Finds the source directory for the installation, asks the user
  2312. to insert the disk. And returns */
  2313. BRC BrcInsertDisk(CHAR *pchStf, CHAR *pchSrcDrive)
  2314. {
  2315. CHAR rgbBuf[_MAX_PATH];
  2316. BYTE rgbFileBuf[32];
  2317. UINT iFileBuf = sizeof(rgbFileBuf), cFileBuf = sizeof(rgbFileBuf);
  2318. CHAR *pchBuf = rgbBuf;
  2319. CHAR *pchMsg;
  2320. int iStf = 0;
  2321. HFILE hFile;
  2322. BRC brc = brcLst;
  2323. char chDrv;
  2324. BOOL fQuote = FALSE;
  2325. int drvType;
  2326. BOOL fFirst = TRUE;
  2327. BOOL fOpen = FALSE;
  2328. HFILE hFileT;
  2329. BOOL fRenameStf = fFalse;
  2330. if ((hFile = _lopen(pchStf, OF_READ)) == HFILE_ERROR)
  2331. return brcNoStf;
  2332. /* Find the path to the original setup. This is stored in the .stf file on the
  2333. Source Directory line */
  2334. while (pchBuf < rgbBuf + sizeof(rgbBuf))
  2335. {
  2336. BYTE ch;
  2337. if (iFileBuf == cFileBuf)
  2338. {
  2339. if ((cFileBuf = _lread(hFile, rgbFileBuf, sizeof(rgbFileBuf))) == 0)
  2340. goto LDone;
  2341. iFileBuf = 0;
  2342. }
  2343. ch = rgbFileBuf[iFileBuf++];
  2344. if (iStf < cchStfSrcDir)
  2345. {
  2346. if (ch == szcStfSrcDir[iStf])
  2347. iStf++;
  2348. else
  2349. iStf = 0;
  2350. continue;
  2351. }
  2352. if(fQuote)
  2353. fQuote = FALSE;
  2354. else if (ch == '"')
  2355. {
  2356. fQuote = TRUE;
  2357. continue;
  2358. }
  2359. else if (ch == '\x0d' || ch == '\t')
  2360. break;
  2361. *pchBuf++ = (CHAR)ch;
  2362. /* Case of having the last character be a DBCS character */
  2363. if (IsDBCSLeadByte(ch))
  2364. {
  2365. if (iFileBuf == cFileBuf)
  2366. {
  2367. _lread(hFile, &ch, 1);
  2368. *pchBuf++ = (CHAR) ch;
  2369. }
  2370. else
  2371. *pchBuf++ = rgbFileBuf[iFileBuf++];
  2372. }
  2373. }
  2374. LDone:
  2375. *pchBuf = 0;
  2376. if (rgbBuf[0] == 0)
  2377. {
  2378. fRenameStf = fTrue;
  2379. goto LClose;
  2380. }
  2381. chDrv = (char)toupper(rgbBuf[0]);
  2382. if (rgbBuf[1] != ':' || chDrv < 'A' || chDrv > 'Z')
  2383. {
  2384. /* We know this is a network drive - UNC Name */
  2385. drvType = EX_DRIVE_REMOTE;
  2386. Assert(rgbBuf[0] == '\\' && rgbBuf[1] == '\\');
  2387. }
  2388. else
  2389. {
  2390. drvType = GetDriveTypeEx(chDrv - 'A');
  2391. }
  2392. lstrcpy(pchSrcDrive, rgbBuf);
  2393. if (*AnsiPrev(rgbBuf, pchBuf) != '\\')
  2394. {
  2395. *pchBuf++ = '\\';
  2396. *pchBuf = 0;
  2397. }
  2398. lstrcat(rgbBuf, "Setup.ini");
  2399. while (!fOpen)
  2400. {
  2401. switch (drvType)
  2402. {
  2403. case EX_DRIVE_FIXED:
  2404. case EX_DRIVE_REMOTE:
  2405. case EX_DRIVE_RAMDISK:
  2406. case EX_DRIVE_INVALID:
  2407. default:
  2408. if (!fFirst)
  2409. {
  2410. /* We've been here before */
  2411. DispErrBrc(brcConnectToSource, TRUE, MB_OK | MB_ICONSTOP, pchSrcDrive, NULL, NULL);
  2412. brc = brcMax;
  2413. goto LClose;
  2414. }
  2415. /* The setup stuff should be available, change directories and go for it */
  2416. break;
  2417. case EX_DRIVE_FLOPPY:
  2418. case EX_DRIVE_REMOVABLE:
  2419. /* Ask to insert disk */
  2420. pchMsg = rgchInsertDiskMsg;
  2421. goto LAskUser;
  2422. break;
  2423. case EX_DRIVE_CDROM:
  2424. /* Ask to insert their CD */
  2425. pchMsg = rgchInsertCDMsg;
  2426. LAskUser:
  2427. if (fFirst)
  2428. {
  2429. if (DispErrBrc(brcString, FALSE, MB_ICONEXCLAMATION|MB_OKCANCEL,
  2430. pchMsg, NULL, NULL) != IDOK)
  2431. {
  2432. brc = brcUserQuit;
  2433. goto LClose;
  2434. }
  2435. }
  2436. else
  2437. {
  2438. if (DispErrBrc(brcInsCDRom2, FALSE, MB_ICONEXCLAMATION|MB_OKCANCEL,
  2439. rgbBuf, pchMsg, NULL) != IDOK)
  2440. {
  2441. brc = brcUserQuit;
  2442. goto LClose;
  2443. }
  2444. }
  2445. break;
  2446. }
  2447. if ((hFileT = _lopen(rgbBuf, OF_READ)) != HFILE_ERROR)
  2448. {
  2449. _lclose(hFileT);
  2450. fOpen = fTrue;
  2451. }
  2452. fFirst = FALSE;
  2453. }
  2454. brc = brcOkay;
  2455. LClose:
  2456. _lclose(hFile);
  2457. /* If we can't find the source path in the maintenance mode .STF,
  2458. * assume it's corrupted and rename it, so when the user runs again
  2459. * from the source image, we will just run in 'floppy' mode,
  2460. * avoiding the bad .STF file.
  2461. * (NOTE: Assumes /W is only used in maint mode!!)
  2462. */
  2463. if (fRenameStf)
  2464. {
  2465. FRenameBadMaintStf(pchStf);
  2466. brc = brcNoStf;
  2467. }
  2468. return brc;
  2469. }
  2470. /*
  2471. ****************************************************************************/
  2472. BOOL FRenameBadMaintStf ( SZ szStf )
  2473. {
  2474. CHAR rgch[_MAX_FNAME];
  2475. _splitpath(szStf, szNull, szNull, rgch, szNull);
  2476. if (*rgch == '\0')
  2477. lstrcpy(rgch, "stf");
  2478. Assert(lstrlen(rgch) + 4 < sizeof rgch);
  2479. lstrcat(rgch, ".000");
  2480. rename(szStf, rgch);
  2481. /* Remove the original .STF in case the rename failed
  2482. * (probably due to a previously renamed .STF file).
  2483. */
  2484. remove(szStf);
  2485. return (fTrue); /* Always returns true */
  2486. }