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.

624 lines
21 KiB

  1. #include <windows.h>
  2. #include <regstr.h>
  3. #include <shellapi.h>
  4. #include "cdinst.h"
  5. #include "resource.h"
  6. // global variables
  7. HINSTANCE g_hInst;
  8. CHAR g_szTitle[128];
  9. CHAR g_szSrcDir[MAX_PATH], g_szDstDir[MAX_PATH];
  10. int _stdcall ModuleEntry(void)
  11. {
  12. int i;
  13. STARTUPINFO si;
  14. LPSTR pszCmdLine = GetCommandLine();
  15. if ( *pszCmdLine == '\"' ) {
  16. /*
  17. * Scan, and skip over, subsequent characters until
  18. * another double-quote or a null is encountered.
  19. */
  20. while ( *++pszCmdLine && (*pszCmdLine != '\"') )
  21. ;
  22. /*
  23. * If we stopped on a double-quote (usual case), skip
  24. * over it.
  25. */
  26. if ( *pszCmdLine == '\"' )
  27. pszCmdLine++;
  28. }
  29. else {
  30. while (*pszCmdLine > ' ')
  31. pszCmdLine++;
  32. }
  33. /*
  34. * Skip past any white space preceeding the second token.
  35. */
  36. while (*pszCmdLine && (*pszCmdLine <= ' ')) {
  37. pszCmdLine++;
  38. }
  39. si.dwFlags = 0;
  40. GetStartupInfoA(&si);
  41. i = WinMain(GetModuleHandle(NULL), NULL, pszCmdLine,
  42. si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
  43. ExitProcess(i);
  44. return i; // We never comes here.
  45. }
  46. INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pszCmdLine, INT iCmdShow)
  47. {
  48. BOOL bIniCopiedToTemp = FALSE;
  49. CHAR szIniFile[MAX_PATH], szSrcDir[MAX_PATH], szDstDir[MAX_PATH];
  50. LPSTR pszSection, pszPtr, pszLine, pszFile, pszSrcSubDir, pszDstSubDir;
  51. DWORD dwLen, dwSpaceReq, dwSpaceFree;
  52. g_hInst = hInstance;
  53. LoadString(g_hInst, IDS_TITLE, g_szTitle, sizeof(g_szTitle));
  54. ParseCmdLine(pszCmdLine);
  55. if (*g_szSrcDir == '\0')
  56. {
  57. if (GetModuleFileName(g_hInst, g_szSrcDir, sizeof(g_szSrcDir)))
  58. if ((pszPtr = ANSIStrRChr(g_szSrcDir, '\\')) != NULL)
  59. *pszPtr = '\0';
  60. if (*g_szSrcDir == '\0')
  61. {
  62. ErrorMsg(IDS_SRCDIR_NOT_FOUND);
  63. return -1;
  64. }
  65. }
  66. if (*g_szDstDir == '\0')
  67. {
  68. HKEY hk;
  69. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_APPPATHS "\\ieak6wiz.exe", 0, KEY_READ, &hk) == ERROR_SUCCESS)
  70. {
  71. dwLen = sizeof(g_szDstDir);
  72. RegQueryValueEx(hk, "Path", NULL, NULL, (LPBYTE) g_szDstDir, &dwLen);
  73. RegCloseKey(hk);
  74. }
  75. if (*g_szDstDir == '\0')
  76. {
  77. ErrorMsg(IDS_DESTDIR_NOT_FOUND);
  78. return -1;
  79. }
  80. }
  81. // look for cdinst.ini in the dir where the parent module (ieak6cd.exe) is running from
  82. *szIniFile = '\0';
  83. lstrcpy(szIniFile, g_szSrcDir);
  84. AddPath(szIniFile, "cdinst.ini");
  85. if (!FileExists(szIniFile))
  86. {
  87. // not found where ieak6cd.exe is running from; so look for it in the dir where the current
  88. // module (cdinst.exe) is running from
  89. *szIniFile = '\0';
  90. if (GetModuleFileName(g_hInst, szIniFile, sizeof(szIniFile)))
  91. {
  92. if ((pszPtr = ANSIStrRChr(szIniFile, '\\')) != NULL)
  93. *pszPtr = '\0';
  94. AddPath(szIniFile, "cdinst.ini");
  95. }
  96. if (!FileExists(szIniFile))
  97. {
  98. *szIniFile = '\0';
  99. GetModuleFileName(g_hInst, szIniFile, sizeof(szIniFile));
  100. ErrorMsg(IDS_INI_NOT_FOUND, g_szSrcDir, szIniFile);
  101. return -1;
  102. }
  103. }
  104. // copy cdinst.ini to the temp dir -- need to do this because on Win95, if cdinst.ini
  105. // is at the same location as ieak6cd.exe on a read-only media (like CD), then
  106. // GetPrivateProfileSection() calls would fail.
  107. // NOTE: szSrcDir and szDstDir are used as temp variables below
  108. if (GetTempPath(sizeof(szSrcDir), szSrcDir))
  109. if (GetTempFileName(szSrcDir, "cdinst", 0, szDstDir))
  110. if (CopyFile(szIniFile, szDstDir, FALSE))
  111. {
  112. bIniCopiedToTemp = TRUE;
  113. lstrcpy(szIniFile, szDstDir);
  114. SetFileAttributes(szIniFile, FILE_ATTRIBUTE_NORMAL);
  115. }
  116. // NOTE: If the destination dir is a UNC path, GetFreeDiskSpace() won't return the right value on Win95 Gold.
  117. // So we turn off disk space checking if installing to a UNC path.
  118. while (!EnoughDiskSpace(g_szSrcDir, g_szDstDir, szIniFile, &dwSpaceReq, &dwSpaceFree))
  119. {
  120. if (ErrorMsg(IDS_NOT_ENOUGH_DISK_SPACE, dwSpaceReq, dwSpaceFree) == IDNO)
  121. return -1;
  122. }
  123. // copy files that are specified in the [copy] section
  124. // format of a line in the [copy] section is (all the fields should be on one line):
  125. // <file (can contain wildcards)>,
  126. // <src sub dir (can be a relative path) - optional>,
  127. // <dest sub dir (can be a relative path) - optional>
  128. if (ReadSectionFromInf("Copy", &pszSection, &dwLen, szIniFile))
  129. {
  130. for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1)
  131. {
  132. ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, &pszDstSubDir);
  133. GetDirPath(g_szSrcDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), szIniFile);
  134. GetDirPath(g_szDstDir, pszDstSubDir, szDstDir, sizeof(szDstDir), szIniFile);
  135. CopyFiles(szSrcDir, pszFile, szDstDir, FALSE);
  136. }
  137. }
  138. if (pszSection != NULL)
  139. LocalFree(pszSection);
  140. // delete files that are specified in the [exclude] section from the destination dir
  141. // format of a line in the [exclude] section is (all the fields should be on one line):
  142. // <file (can contain wildcards)>,
  143. // <dest sub dir (can be a relative path) - optional>
  144. if (ReadSectionFromInf("Exclude", &pszSection, &dwLen, szIniFile))
  145. {
  146. for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1)
  147. {
  148. ParseIniLine(pszLine, &pszFile, NULL, &pszDstSubDir);
  149. GetDirPath(g_szDstDir, pszDstSubDir, szDstDir, sizeof(szDstDir), szIniFile);
  150. DelFiles(pszFile, szDstDir);
  151. }
  152. }
  153. if (pszSection != NULL)
  154. LocalFree(pszSection);
  155. // extract all the files from cabs that are specified in the [extract] section
  156. // format of a line in the [extract] section is (all the fields should be on one line):
  157. // <cab file (can contain wildcards)>,
  158. // <src sub dir (can be a relative path) - optional>,
  159. // <dest sub dir (can be a relative path) - optional>
  160. if (ReadSectionFromInf("Extract", &pszSection, &dwLen, szIniFile))
  161. {
  162. HINSTANCE hAdvpack;
  163. if ((hAdvpack = LoadLibrary("advpack.dll")) != NULL)
  164. {
  165. EXTRACTFILES pfnExtractFiles;
  166. if ((pfnExtractFiles = (EXTRACTFILES) GetProcAddress(hAdvpack, "ExtractFiles")) != NULL)
  167. {
  168. for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1)
  169. {
  170. ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, &pszDstSubDir);
  171. GetDirPath(g_szSrcDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), szIniFile);
  172. GetDirPath(g_szDstDir, pszDstSubDir, szDstDir, sizeof(szDstDir), szIniFile);
  173. ExtractFiles(szSrcDir, pszFile, szDstDir, pfnExtractFiles);
  174. }
  175. }
  176. FreeLibrary(hAdvpack);
  177. }
  178. }
  179. if (pszSection != NULL)
  180. LocalFree(pszSection);
  181. // move files that are specified in the [move] section from a subdir to another subdir under the destination dir
  182. // format of a line in the [move] section is (all the fields should be on one line):
  183. // <file (can contain wildcards)>,
  184. // <from sub dir under the dest dir (can be a relative path) - optional>,
  185. // <to sub dir under the dest dir (can be a relative path) - optional>
  186. if (ReadSectionFromInf("Move", &pszSection, &dwLen, szIniFile))
  187. {
  188. for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1)
  189. {
  190. ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, &pszDstSubDir);
  191. GetDirPath(g_szDstDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), szIniFile);
  192. GetDirPath(g_szDstDir, pszDstSubDir, szDstDir, sizeof(szDstDir), szIniFile);
  193. MoveFiles(szSrcDir, pszFile, szDstDir);
  194. }
  195. }
  196. if (pszSection != NULL)
  197. LocalFree(pszSection);
  198. if (bIniCopiedToTemp)
  199. DeleteFile(szIniFile);
  200. return 0;
  201. }
  202. BOOL EnoughDiskSpace(LPCSTR pcszSrcRootDir, LPCSTR pcszDstRootDir, LPCSTR pcszIniFile, LPDWORD pdwSpaceReq, LPDWORD pdwSpaceFree)
  203. // check if there is enough free disk space to copy all the files
  204. {
  205. DWORD dwSpaceReq = 0, dwSpaceFree;
  206. CHAR szSrcDir[MAX_PATH], szDstDir[MAX_PATH];
  207. LPSTR pszSection, pszLine, pszFile, pszSrcSubDir, pszDstSubDir;
  208. DWORD dwLen, dwFlags;
  209. if (!GetFreeDiskSpace(pcszDstRootDir, &dwSpaceFree, &dwFlags))
  210. {
  211. // if we can't get FreeDiskSpace info, then turn off disk space checking
  212. return TRUE;
  213. }
  214. // total space required =
  215. // size of all the files to be copied +
  216. // 2 * size of all the files to be extracted
  217. if (ReadSectionFromInf("Copy", &pszSection, &dwLen, pcszIniFile))
  218. {
  219. for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1)
  220. {
  221. ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, &pszDstSubDir);
  222. GetDirPath(pcszSrcRootDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), pcszIniFile);
  223. GetDirPath(pcszDstRootDir, pszDstSubDir, szDstDir, sizeof(szDstDir), pcszIniFile);
  224. dwSpaceReq += FindSpaceRequired(szSrcDir, pszFile, szDstDir);
  225. }
  226. }
  227. if (pszSection != NULL)
  228. LocalFree(pszSection);
  229. if (ReadSectionFromInf("Extract", &pszSection, &dwLen, pcszIniFile))
  230. {
  231. for (pszLine = pszSection; dwLen = lstrlen(pszLine); pszLine += dwLen + 1)
  232. {
  233. ParseIniLine(pszLine, &pszFile, &pszSrcSubDir, NULL);
  234. GetDirPath(pcszSrcRootDir, pszSrcSubDir, szSrcDir, sizeof(szSrcDir), pcszIniFile);
  235. dwSpaceReq += 2 * FindSpaceRequired(szSrcDir, pszFile, NULL);
  236. }
  237. }
  238. if (pszSection != NULL)
  239. LocalFree(pszSection);
  240. dwSpaceReq += 1024; // 1MB buffer to account for random stuff
  241. if (dwFlags & FS_VOL_IS_COMPRESSED)
  242. {
  243. // if the destination volume is compressed, the free space returned is only
  244. // a guesstimate; for example, if it's a DoubleSpace volume, the system thinks
  245. // that it can compress by 50% and so it reports the free space as (actual free space * 2)
  246. // it's better to be safe when dealing with compressed volumes; so bump up the space
  247. // requirement by a factor 2
  248. dwSpaceReq <<= 1; // multiply by 2
  249. }
  250. if (pdwSpaceReq != NULL)
  251. *pdwSpaceReq = dwSpaceReq;
  252. if (pdwSpaceFree != NULL)
  253. *pdwSpaceFree = dwSpaceFree;
  254. return dwSpaceFree > dwSpaceReq;
  255. }
  256. BOOL GetFreeDiskSpace(LPCSTR pcszDir, LPDWORD pdwFreeSpace, LPDWORD pdwFlags)
  257. // Return the free disk space (in KBytes) in *pdwFreeSpace
  258. {
  259. BOOL bRet = FALSE;
  260. DWORD dwFreeSpace = 0;
  261. DWORD nSectorsPerCluster, nBytesPerSector, nFreeClusters, nTotalClusters;
  262. CHAR szDrive[8];
  263. if (pcszDir == NULL || *pcszDir == '\0' || *(pcszDir + 1) != ':')
  264. return FALSE;
  265. if (pdwFreeSpace == NULL)
  266. return FALSE;
  267. lstrcpyn(szDrive, pcszDir, 3);
  268. AddPath(szDrive, NULL);
  269. if (GetDiskFreeSpace(szDrive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters))
  270. {
  271. // convert size to KBytes; assumption here is that the free space doesn't exceed 4096 gigs
  272. if ((*pdwFreeSpace = MulDiv(nFreeClusters, nSectorsPerCluster * nBytesPerSector, 1024)) != (DWORD) -1)
  273. {
  274. bRet = TRUE;
  275. if (pdwFlags != NULL)
  276. {
  277. *pdwFlags = 0;
  278. GetVolumeInformation(szDrive, NULL, 0, NULL, NULL, pdwFlags, NULL, 0);
  279. }
  280. }
  281. }
  282. return bRet;
  283. }
  284. DWORD FindSpaceRequired(LPCSTR pcszSrcDir, LPCSTR pcszFile, LPCSTR pcszDstDir)
  285. // Return the difference in size (in KBytes) of pcszFile (can contain wildcards)
  286. // under pcszSrcDir and pcszDstDir (if specified)
  287. {
  288. DWORD dwSizeReq = 0;
  289. CHAR szSrcFile[MAX_PATH], szDstFile[MAX_PATH];
  290. LPSTR pszSrcPtr, pszDstPtr;
  291. WIN32_FIND_DATA fileData;
  292. HANDLE hFindFile;
  293. lstrcpy(szSrcFile, pcszSrcDir);
  294. AddPath(szSrcFile, NULL);
  295. pszSrcPtr = szSrcFile + lstrlen(szSrcFile);
  296. if (pcszDstDir != NULL)
  297. {
  298. lstrcpy(szDstFile, pcszDstDir);
  299. AddPath(szDstFile, NULL);
  300. pszDstPtr = szDstFile + lstrlen(szDstFile);
  301. }
  302. lstrcpy(pszSrcPtr, pcszFile);
  303. if ((hFindFile = FindFirstFile(szSrcFile, &fileData)) != INVALID_HANDLE_VALUE)
  304. {
  305. do
  306. {
  307. if (!(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  308. {
  309. DWORD dwSrcSize, dwDstSize;
  310. // assumption here is that the size of the file doesn't exceed 4 gigs
  311. dwSrcSize = fileData.nFileSizeLow;
  312. dwDstSize = 0;
  313. if (pcszDstDir != NULL)
  314. {
  315. lstrcpy(pszDstPtr, fileData.cFileName);
  316. dwDstSize = FileSize(szDstFile);
  317. }
  318. if (dwSrcSize >= dwDstSize)
  319. {
  320. // divide the difference by 1024 (we are interested in KBytes)
  321. dwSizeReq += ((dwSrcSize - dwDstSize) >> 10);
  322. if (dwSrcSize > dwDstSize)
  323. dwSizeReq++; // increment by 1 to promote any fraction to a whole number
  324. }
  325. }
  326. } while (FindNextFile(hFindFile, &fileData));
  327. FindClose(hFindFile);
  328. }
  329. return dwSizeReq;
  330. }
  331. VOID ParseIniLine(LPSTR pszLine, LPSTR *ppszFile, LPSTR *ppszSrcDir, LPSTR *ppszDstDir)
  332. {
  333. if (ppszFile != NULL)
  334. *ppszFile = Trim(GetNextField(&pszLine, ",", REMOVE_QUOTES));
  335. if (ppszSrcDir != NULL)
  336. *ppszSrcDir = Trim(GetNextField(&pszLine, ",", REMOVE_QUOTES));
  337. if (ppszDstDir != NULL)
  338. *ppszDstDir = Trim(GetNextField(&pszLine, ",", REMOVE_QUOTES));
  339. }
  340. LPSTR GetDirPath(LPCSTR pcszRootDir, LPCSTR pcszSubDir, CHAR szDirPath[], DWORD cchBuffer, LPCSTR pcszIniFile)
  341. {
  342. *szDirPath = '\0';
  343. if (pcszRootDir == NULL)
  344. return NULL;
  345. lstrcpyn(szDirPath, pcszRootDir, cchBuffer);
  346. if (pcszSubDir != NULL && *pcszSubDir)
  347. {
  348. CHAR szTemp[MAX_PATH];
  349. // if there are any placeholders in pcszSubDir (%en%, etc), ReplacePlaceholders will replace
  350. // them with the actual strings
  351. if (ReplacePlaceholders(pcszSubDir, pcszIniFile, szTemp, sizeof(szTemp)))
  352. {
  353. if ((DWORD) lstrlen(szDirPath) + 1 < cchBuffer) // there is room for '\\' which AddPath
  354. // might append to szDirPath (see below)
  355. {
  356. INT iLen;
  357. AddPath(szDirPath, NULL); // we have enough room in szDirPath for '\\'
  358. if (cchBuffer > (DWORD) (iLen = lstrlen(szDirPath)))
  359. lstrcpyn(szDirPath + iLen, szTemp, cchBuffer - iLen);
  360. }
  361. }
  362. }
  363. return szDirPath;
  364. }
  365. DWORD ReplacePlaceholders(LPCSTR pszSrc, LPCSTR pszIns, LPSTR pszBuffer, DWORD cchBuffer)
  366. {
  367. LPCSTR pszAux;
  368. CHAR szResult[MAX_PATH];
  369. UINT nDestPos, nLeftPos;
  370. nDestPos = 0;
  371. nLeftPos = (UINT) -1;
  372. for (pszAux = pszSrc; *pszAux; pszAux = CharNext(pszAux))
  373. {
  374. if (*pszAux != '%')
  375. {
  376. szResult[nDestPos++] = *pszAux;
  377. if (IsDBCSLeadByte(*pszAux))
  378. szResult[nDestPos++] = *(pszAux + 1); // copy the trail byte as well
  379. }
  380. else if (*(pszAux + 1) == '%') // "%%" is just '%' in the string
  381. {
  382. if (nLeftPos != (UINT) -1)
  383. // REVIEW: (andrewgu) "%%" are not allowed inside tokens. this also means that
  384. // tokens can't be like %foo%%bar%, where the intention is for foo and bar to
  385. // be tokens.
  386. return 0;
  387. szResult[nDestPos++] = *pszAux++;
  388. }
  389. else
  390. {
  391. UINT nRightPos;
  392. nRightPos = (UINT) (pszAux - pszSrc); // initialized, but not necessarily used as such
  393. if (nLeftPos == (UINT) -1)
  394. nLeftPos = nRightPos;
  395. else
  396. {
  397. CHAR szAux1[MAX_PATH], szAux2[MAX_PATH];
  398. DWORD dwLen;
  399. UINT nTokenLen;
  400. // "%%" is invalid here
  401. nTokenLen = nRightPos - nLeftPos - 1;
  402. lstrcpyn(szAux1, pszSrc + nLeftPos + 1, nTokenLen + 1);
  403. if ((dwLen = GetPrivateProfileString("Strings", szAux1, "", szAux2, sizeof(szAux2), pszIns)))
  404. {
  405. lstrcpy(&szResult[nDestPos - nTokenLen], szAux2);
  406. nDestPos += dwLen - nTokenLen;
  407. }
  408. nLeftPos = (UINT) -1;
  409. }
  410. }
  411. }
  412. if (nLeftPos != (UINT) -1) // mismatched '%'
  413. return 0;
  414. if (cchBuffer <= nDestPos) // insufficient buffer size
  415. return 0;
  416. szResult[nDestPos] = '\0'; // make sure zero terminated
  417. lstrcpy(pszBuffer, szResult);
  418. return nDestPos;
  419. }
  420. VOID SetAttribsToNormal(LPCSTR pcszFile, LPCSTR pcszDir)
  421. // Set the attribs of pcszFile (can contain wildcards) under pcszDir to NORMAL
  422. {
  423. CHAR szFile[MAX_PATH];
  424. LPSTR pszPtr;
  425. WIN32_FIND_DATA fileData;
  426. HANDLE hFindFile;
  427. lstrcpy(szFile, pcszDir);
  428. AddPath(szFile, NULL);
  429. pszPtr = szFile + lstrlen(szFile);
  430. lstrcpy(pszPtr, pcszFile);
  431. if ((hFindFile = FindFirstFile(szFile, &fileData)) != INVALID_HANDLE_VALUE)
  432. {
  433. do
  434. {
  435. if (!(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  436. {
  437. lstrcpy(pszPtr, fileData.cFileName);
  438. SetFileAttributes(szFile, FILE_ATTRIBUTE_NORMAL);
  439. }
  440. } while (FindNextFile(hFindFile, &fileData));
  441. FindClose(hFindFile);
  442. }
  443. }
  444. VOID CopyFiles(LPCSTR pcszSrcDir, LPCSTR pcszFile, LPCSTR pcszDstDir, BOOL fQuiet)
  445. {
  446. SHFILEOPSTRUCT shfStruc;
  447. CHAR szSrcFiles[MAX_PATH + 1];
  448. if (!PathExists(pcszDstDir))
  449. PathCreatePath(pcszDstDir);
  450. else
  451. {
  452. // set the attribs of files under pcszDstDir to NORMAL so that on a reinstall,
  453. // SHFileOperation doesn't choke on read-only files
  454. SetAttribsToNormal(pcszFile, pcszDstDir);
  455. }
  456. ZeroMemory(szSrcFiles, sizeof(szSrcFiles));
  457. lstrcpy(szSrcFiles, pcszSrcDir);
  458. AddPath(szSrcFiles, pcszFile);
  459. ZeroMemory(&shfStruc, sizeof(shfStruc));
  460. shfStruc.hwnd = NULL;
  461. shfStruc.wFunc = FO_COPY;
  462. shfStruc.pFrom = szSrcFiles;
  463. shfStruc.pTo = pcszDstDir;
  464. shfStruc.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
  465. if (fQuiet)
  466. shfStruc.fFlags |= FOF_SILENT;
  467. SHFileOperation(&shfStruc);
  468. }
  469. VOID DelFiles(LPCSTR pcszFile, LPCSTR pcszDstDir)
  470. {
  471. SHFILEOPSTRUCT shfStruc;
  472. CHAR szDstFiles[MAX_PATH + 1];
  473. // set the attribs of files under pcszDstDir to NORMAL so that
  474. // SHFileOperation doesn't choke on read-only files
  475. SetAttribsToNormal(pcszFile, pcszDstDir);
  476. ZeroMemory(szDstFiles, sizeof(szDstFiles));
  477. lstrcpy(szDstFiles, pcszDstDir);
  478. AddPath(szDstFiles, pcszFile);
  479. ZeroMemory(&shfStruc, sizeof(shfStruc));
  480. shfStruc.hwnd = NULL;
  481. shfStruc.wFunc = FO_DELETE;
  482. shfStruc.pFrom = szDstFiles;
  483. shfStruc.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
  484. SHFileOperation(&shfStruc);
  485. }
  486. VOID ExtractFiles(LPCSTR pcszSrcDir, LPCSTR pcszFile, LPCSTR pcszDstDir, EXTRACTFILES pfnExtractFiles)
  487. {
  488. CHAR szSrcCab[MAX_PATH];
  489. lstrcpy(szSrcCab, pcszSrcDir);
  490. AddPath(szSrcCab, pcszFile);
  491. // NOTE: ExtractFiles fails if the dest dir doesn't exist
  492. if (!PathExists(pcszDstDir))
  493. PathCreatePath(pcszDstDir);
  494. else
  495. {
  496. // set the attribs of all the files under pcszDstDir to NORMAL so that on a reinstall,
  497. // ExtractFiles doesn't choke on read-only files
  498. SetAttribsToNormal("*.*", pcszDstDir);
  499. }
  500. pfnExtractFiles(szSrcCab, pcszDstDir, 0, NULL, NULL, 0);
  501. }
  502. VOID MoveFiles(LPCSTR pcszSrcDir, LPCSTR pcszFile, LPCSTR pcszDstDir)
  503. {
  504. // Can't use SHFileOperation to move files because on a reinstall,
  505. // we get an error saying that the target files already exist.
  506. // Workaround is to call CopyFiles and then DelFiles.
  507. CopyFiles(pcszSrcDir, pcszFile, pcszDstDir, TRUE);
  508. DelFiles(pcszFile, pcszSrcDir);
  509. }