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.

2748 lines
80 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include "muisetup.h"
  5. #include "stdlib.h"
  6. #include "tchar.h"
  7. #include <setupapi.h>
  8. #include <syssetup.h>
  9. #include "lzexpand.h"
  10. #include <shlwapi.h>
  11. #include <sxsapi.h>
  12. #include <shlwapip.h> // For SHRegisterValidateTemplate()
  13. #define SHRVT_REGISTER 0x00000001
  14. #define DEFAULT_INSTALL_SECTION TEXT("DefaultInstall")
  15. #define DEFAULT_UNINSTALL_SECTION TEXT("DefaultUninstall")
  16. // GLOBAL variables
  17. extern TCHAR DirNames[MFL][MAX_PATH],DirNames_ie[MFL][MAX_PATH];
  18. LPTSTR g_szSpecialFiles[] = {
  19. TEXT("hhctrlui.dll"),
  20. };
  21. void debug(char *printout);
  22. ////////////////////////////////////////////////////////////////////////////////////
  23. //
  24. // EnumLanguages
  25. //
  26. // Enumerate the languages in the [Languages] section of MUI.INF. And check for the language
  27. // folders in the CD-ROM.
  28. // Languages is an OUT parameter, which will store the languages which has language folder
  29. // in the CD-ROM.
  30. //
  31. ////////////////////////////////////////////////////////////////////////////////////
  32. int EnumLanguages(LPTSTR Languages, BOOL bCheckDir)
  33. {
  34. DWORD dwErr;
  35. LPTSTR Language;
  36. LONG_PTR lppArgs[1];
  37. TCHAR lpError[BUFFER_SIZE];
  38. TCHAR lpMessage[BUFFER_SIZE];
  39. TCHAR szInffile[MAX_PATH];
  40. int iLanguages = 0;
  41. //
  42. // MUI.INF should be in the same directory in which the installer was
  43. // started
  44. //
  45. _tcscpy(szInffile, g_szMUIInfoFilePath);
  46. //
  47. // find out how many languages we can install
  48. //
  49. *Languages = TEXT('\0');
  50. if (!GetPrivateProfileString( MUI_LANGUAGES_SECTION,
  51. NULL,
  52. TEXT("NOLANG"),
  53. Languages,
  54. BUFFER_SIZE,
  55. szInffile))
  56. {
  57. //
  58. // "LOG: Unable to read MUI.INF - rc == %1"
  59. //
  60. lppArgs[0] = (LONG_PTR)GetLastError();
  61. LogFormattedMessage(ghInstance, IDS_NO_READ_L, lppArgs);
  62. return(-1);
  63. }
  64. if (bCheckDir)
  65. {
  66. CheckLanguageDirectoryExist(Languages);
  67. }
  68. Language = Languages;
  69. //
  70. // Count the number of languages which exist in the CD-ROM,
  71. // and return that value.
  72. //
  73. while (*Language)
  74. {
  75. iLanguages++;
  76. while (*Language++)
  77. {
  78. }
  79. }
  80. return(iLanguages);
  81. }
  82. BOOL CheckLanguageDirectoryExist(LPTSTR Languages)
  83. {
  84. TCHAR szBuffer[BUFFER_SIZE];
  85. TCHAR szSource[ MAX_PATH ];
  86. TCHAR szTemp [ MAX_PATH ];
  87. LPTSTR lpCur,lpBuffer;
  88. HANDLE hFile;
  89. WIN32_FIND_DATA FindFileData;
  90. memcpy(szBuffer,Languages,BUFFER_SIZE);
  91. lpCur=Languages;
  92. lpBuffer=szBuffer;
  93. while (*lpBuffer)
  94. {
  95. GetPrivateProfileString( MUI_LANGUAGES_SECTION,
  96. lpBuffer,
  97. TEXT("DEFAULT"),
  98. szSource,
  99. (sizeof(szSource)/sizeof(TCHAR)),
  100. g_szMUIInfoFilePath );
  101. _tcscpy(szTemp,g_szMUISetupFolder);
  102. _tcscat(szTemp,szSource);
  103. _tcscat(szTemp,TEXT("\\"));
  104. _tcscat(szTemp,g_szPlatformPath); // i386 or alpha
  105. _tcscat(szTemp,TEXT("*.*"));
  106. hFile = FindFirstFile( szTemp, &FindFileData );
  107. if (INVALID_HANDLE_VALUE != hFile )
  108. {
  109. if (FindNextFile( hFile, &FindFileData ) &&
  110. FindNextFile( hFile, &FindFileData ) )
  111. {
  112. _tcscpy(lpCur,lpBuffer);
  113. lpCur+=(_tcslen(lpBuffer)+1);
  114. }
  115. FindClose(hFile);
  116. }
  117. while (*lpBuffer++)
  118. {
  119. }
  120. }
  121. *lpCur=TEXT('\0');
  122. return TRUE;
  123. }
  124. ////////////////////////////////////////////////////////////////////////////////////
  125. //
  126. // checkversion
  127. //
  128. // Checks the NT version and build
  129. //
  130. ////////////////////////////////////////////////////////////////////////////////////
  131. BOOL checkversion(BOOL bMatchBuildNumber)
  132. {
  133. TCHAR buffer[20];
  134. TCHAR build[20];
  135. OSVERSIONINFO verinfo;
  136. LANGID rcLang;
  137. TCHAR lpMessage[BUFFER_SIZE];
  138. verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  139. GetVersionEx( &verinfo) ;
  140. if (verinfo.dwMajorVersion < 5)
  141. {
  142. debug("DBG: Need Windows NT version 5 or greater\r\n");
  143. return (FALSE);
  144. }
  145. rcLang = (LANGID) gpfnGetSystemDefaultUILanguage();
  146. //
  147. // need to convert decimal to hex, LANGID to chr.
  148. //
  149. _stprintf(buffer,TEXT("00000%X"), rcLang);
  150. if (_tcscmp(buffer, TEXT("00000409")))
  151. {
  152. return(FALSE);
  153. }
  154. if (bMatchBuildNumber && FileExists(g_szMUIInfoFilePath))
  155. {
  156. GetPrivateProfileString( TEXT("Buildnumber"),
  157. NULL,
  158. TEXT("0"),
  159. buffer,
  160. (sizeof(buffer)/ sizeof(TCHAR)),
  161. g_szMUIInfoFilePath);
  162. _stprintf(build, TEXT("%d"), verinfo.dwBuildNumber);
  163. if (!_tcscmp(buffer, TEXT("-1")))
  164. {
  165. //
  166. // "LOG: No version check forced by MUI.INF"
  167. //
  168. LoadString(ghInstance, IDS_NO_CHECK_L, lpMessage, ARRAYSIZE(lpMessage)-1);
  169. LogMessage(lpMessage);
  170. return TRUE;
  171. }
  172. if (_tcscmp(buffer, build))
  173. {
  174. debug(" wrong build.\r\n");
  175. return FALSE;
  176. }
  177. }
  178. return(TRUE);
  179. }
  180. ////////////////////////////////////////////////////////////////////////////////////
  181. //
  182. // File Exists
  183. //
  184. // Returns TRUE if the file exists, FALSE if it does not.
  185. //
  186. ////////////////////////////////////////////////////////////////////////////////////
  187. BOOL FileExists(LPTSTR szFile)
  188. {
  189. HANDLE hFile;
  190. WIN32_FIND_DATA FindFileData;
  191. hFile = FindFirstFile( szFile, &FindFileData );
  192. if (hFile == INVALID_HANDLE_VALUE)
  193. {
  194. return FALSE;
  195. }
  196. FindClose( hFile );
  197. return TRUE;
  198. }
  199. ////////////////////////////////////////////////////////////////////////////////////
  200. //
  201. // EnumDirectories
  202. //
  203. // Enumerates the directories listed in MUI.INF
  204. //
  205. ////////////////////////////////////////////////////////////////////////////////////
  206. BOOL EnumDirectories()
  207. {
  208. DWORD dwErr;
  209. LPTSTR Directories, Directory, TempDir;
  210. TCHAR lpError[BUFFER_SIZE];
  211. TCHAR lpMessage[BUFFER_SIZE];
  212. LONG_PTR lppArgs[3];
  213. int Dirnumber = 0;
  214. Directories = (LPTSTR) LocalAlloc( 0, (DIRNUMBER * MAX_PATH * sizeof(TCHAR)) );
  215. TempDir = (LPTSTR) LocalAlloc( 0, (MAX_PATH * sizeof(TCHAR)) );
  216. if (Directories == NULL || TempDir == NULL)
  217. {
  218. ExitFromOutOfMemory();
  219. }
  220. *Directories = TEXT('\0');
  221. //
  222. // Copy all key names into Directories.
  223. //
  224. if (!GetPrivateProfileString( TEXT("Directories"),
  225. NULL,
  226. TEXT("DEFAULT"),
  227. Directories,
  228. (DIRNUMBER * MAX_PATH),
  229. g_szMUIInfoFilePath ))
  230. {
  231. //
  232. // "LOG: Unable to read - rc == %1"
  233. //
  234. lppArgs[0] = (LONG_PTR)GetLastError();
  235. LogFormattedMessage(ghInstance, IDS_NO_READ_L, lppArgs);
  236. LocalFree( TempDir );
  237. LocalFree( Directories );
  238. return FALSE;
  239. }
  240. Directory = Directories;
  241. //
  242. // In case we don't find anything, we go to the fallback directory
  243. //
  244. _tcscpy(DirNames[0], TEXT("FALLBACK"));
  245. while (*Directory)
  246. {
  247. if (!GetPrivateProfileString( TEXT("Directories"),
  248. Directory,
  249. TEXT("\\DEFAULT"),
  250. TempDir,
  251. MAX_PATH,
  252. g_szMUIInfoFilePath))
  253. {
  254. //
  255. // "LOG: Unable to read - rc == %1"
  256. //
  257. lppArgs[0] = (LONG_PTR)GetLastError();
  258. LogFormattedMessage(ghInstance, IDS_NO_READ_L, lppArgs);
  259. LocalFree( TempDir );
  260. LocalFree( Directories );
  261. return FALSE;
  262. }
  263. _tcscpy(DirNames[++Dirnumber], TempDir);
  264. // Move to the beginning of next key name.
  265. while (*Directory++)
  266. {
  267. }
  268. }
  269. LocalFree( TempDir );
  270. LocalFree( Directories );
  271. return TRUE;
  272. }
  273. ////////////////////////////////////////////////////////////////////////////////////
  274. //
  275. // EnumFileRename
  276. //
  277. // Enumerates the [File_Layout] section listed in MUI.INF
  278. //
  279. ////////////////////////////////////////////////////////////////////////////////////
  280. BOOL EnumFileRename()
  281. {
  282. DWORD dwErr;
  283. LPTSTR Directories, Directory, TempDir,lpszNext;
  284. TCHAR lpError[BUFFER_SIZE];
  285. TCHAR lpMessage[BUFFER_SIZE],szPlatform[MAX_PATH+1],szTargetPlatform[MAX_PATH+1];
  286. LONG_PTR lppArgs[1];
  287. int Dirnumber = 0,nIdx=0;
  288. Directories = (LPTSTR) LocalAlloc( 0, (FILERENAMENUMBER * (MAX_PATH+1) * sizeof(TCHAR)) );
  289. if (!Directories)
  290. {
  291. return FALSE;
  292. }
  293. TempDir = (LPTSTR) LocalAlloc( 0, ( (MAX_PATH+1) * sizeof(TCHAR)) );
  294. if (!TempDir)
  295. {
  296. LocalFree(Directories);
  297. return FALSE;
  298. }
  299. if (gbIsAdvanceServer)
  300. {
  301. _tcscpy(szTargetPlatform,PLATFORMNAME_AS);
  302. }
  303. else if (gbIsServer)
  304. {
  305. _tcscpy(szTargetPlatform,PLATFORMNAME_SRV);
  306. }
  307. else if (gbIsWorkStation)
  308. {
  309. _tcscpy(szTargetPlatform,PLATFORMNAME_PRO);
  310. }
  311. else if ( gbIsDataCenter)
  312. {
  313. _tcscpy(szTargetPlatform,PLATFORMNAME_DTC);
  314. }
  315. else
  316. {
  317. _tcscpy(szTargetPlatform,PLATFORMNAME_PRO);
  318. }
  319. *Directories = TEXT('\0');
  320. if (!GetPrivateProfileString( MUI_FILELAYOUT_SECTION,
  321. NULL,
  322. TEXT(""),
  323. Directories,
  324. (FILERENAMENUMBER * MAX_PATH),
  325. g_szMUIInfoFilePath ))
  326. {
  327. LocalFree( TempDir );
  328. LocalFree( Directories );
  329. return FALSE;
  330. }
  331. Directory = Directories;
  332. //
  333. // Calculate # of entries in this section
  334. //
  335. while (*Directory)
  336. {
  337. if (!GetPrivateProfileString( MUI_FILELAYOUT_SECTION,
  338. Directory,
  339. TEXT(""),
  340. TempDir,
  341. MAX_PATH,
  342. g_szMUIInfoFilePath))
  343. {
  344. LocalFree( TempDir );
  345. LocalFree( Directories );
  346. return FALSE;
  347. }
  348. //
  349. // Check if platform ID field in this entry
  350. //
  351. // Source_file_name=Destination_file_name,P,S,A
  352. //
  353. lpszNext=TempDir;
  354. while ( (lpszNext=_tcschr(lpszNext,TEXT(','))) )
  355. {
  356. lpszNext++;
  357. nIdx=0;
  358. szPlatform[0]=TEXT('\0');
  359. while ( (*lpszNext != TEXT('\0')) && (*lpszNext != TEXT(',')))
  360. {
  361. if (*lpszNext != TEXT(' '))
  362. {
  363. szPlatform[nIdx++]=*lpszNext;
  364. }
  365. lpszNext++;
  366. }
  367. szPlatform[nIdx]=TEXT('\0');
  368. if (!_tcsicmp(szPlatform,szTargetPlatform))
  369. {
  370. Dirnumber++;
  371. break;
  372. }
  373. }
  374. while (*Directory++)
  375. {
  376. }
  377. }
  378. //
  379. // Allocte Space for Rename Table
  380. //
  381. g_pFileRenameTable=(PFILERENAME_TABLE)LocalAlloc( 0, Dirnumber * sizeof(FILERENAME_TABLE) );
  382. if (!g_pFileRenameTable)
  383. {
  384. LocalFree( TempDir );
  385. LocalFree( Directories );
  386. return FALSE;
  387. }
  388. g_nFileRename=0;
  389. Directory = Directories;
  390. //
  391. // Create Reanme Table
  392. //
  393. while (*Directory)
  394. {
  395. if (!GetPrivateProfileString( MUI_FILELAYOUT_SECTION,
  396. Directory,
  397. TEXT(""),
  398. TempDir,
  399. MAX_PATH,
  400. g_szMUIInfoFilePath))
  401. {
  402. LocalFree(g_pFileRenameTable);
  403. LocalFree( TempDir );
  404. LocalFree( Directories );
  405. return FALSE;
  406. }
  407. //
  408. // Check if platform ID field in this entry
  409. //
  410. // Source_file_name=Destination_file_name,P,S,A
  411. //
  412. lpszNext=TempDir;
  413. while ( lpszNext =_tcschr(lpszNext,TEXT(',')))
  414. {
  415. lpszNext++;
  416. nIdx=0;
  417. szPlatform[0]=TEXT('\0');
  418. while ( (*lpszNext != TEXT('\0')) && (*lpszNext != TEXT(',')))
  419. {
  420. if (*lpszNext != TEXT(' '))
  421. {
  422. szPlatform[nIdx++]=*lpszNext;
  423. }
  424. lpszNext++;
  425. }
  426. szPlatform[nIdx]=TEXT('\0');
  427. if (!_tcsicmp(szPlatform,szTargetPlatform) )
  428. {
  429. //
  430. // Insert this entry into rename table pointed by g_pFileRenameTable
  431. //
  432. _tcscpy(g_pFileRenameTable[g_nFileRename].szSource,Directory);
  433. lpszNext=TempDir;
  434. nIdx=0;
  435. g_pFileRenameTable[g_nFileRename].szDest[0]=TEXT('\0');
  436. while ( (*lpszNext != TEXT('\0')) && (*lpszNext != TEXT(',')) && (*lpszNext != TEXT(' ')) )
  437. {
  438. g_pFileRenameTable[g_nFileRename].szDest[nIdx++]=*lpszNext;
  439. lpszNext++;
  440. }
  441. g_pFileRenameTable[g_nFileRename].szDest[nIdx]=TEXT('\0');
  442. g_nFileRename++;
  443. break;
  444. }
  445. }
  446. while (*Directory++)
  447. {
  448. }
  449. }
  450. LocalFree( TempDir );
  451. LocalFree( Directories );
  452. return TRUE;
  453. }
  454. ////////////////////////////////////////////////////////////////////////////////////
  455. //
  456. // EnumTypeNotFallback
  457. //
  458. // Enumerates the [FileType_NoFallback] section listed in MUI.INF
  459. //
  460. ////////////////////////////////////////////////////////////////////////////////////
  461. BOOL EnumTypeNotFallback()
  462. {
  463. LPTSTR Directories, Directory, TempDir,lpszNext;
  464. int Dirnumber = 0,nIdx=0;
  465. Directories = (LPTSTR) LocalAlloc( 0, (NOTFALLBACKNUMBER * (MAX_PATH+1) * sizeof(TCHAR)) );
  466. if (!Directories)
  467. {
  468. return FALSE;
  469. }
  470. TempDir = (LPTSTR) LocalAlloc( 0, ( (MAX_PATH+1) * sizeof(TCHAR)) );
  471. if (!TempDir)
  472. {
  473. LocalFree(Directories);
  474. return FALSE;
  475. }
  476. *Directories = TEXT('\0');
  477. if (!GetPrivateProfileString( MUI_NOFALLBACK_SECTION,
  478. NULL,
  479. TEXT(""),
  480. Directories,
  481. (NOTFALLBACKNUMBER * MAX_PATH),
  482. g_szMUIInfoFilePath ))
  483. {
  484. LocalFree( TempDir );
  485. LocalFree( Directories );
  486. return FALSE;
  487. }
  488. Directory = Directories;
  489. //
  490. // Calculate # of entries in this section
  491. //
  492. while (*Directory)
  493. {
  494. if (!GetPrivateProfileString( MUI_NOFALLBACK_SECTION,
  495. Directory,
  496. TEXT(""),
  497. TempDir,
  498. MAX_PATH,
  499. g_szMUIInfoFilePath))
  500. {
  501. LocalFree( TempDir );
  502. LocalFree( Directories );
  503. return FALSE;
  504. }
  505. Dirnumber++;
  506. while (*Directory++)
  507. {
  508. }
  509. }
  510. //
  511. // Allocte Space for
  512. //
  513. g_pNotFallBackTable=(PTYPENOTFALLBACK_TABLE)LocalAlloc( 0, Dirnumber * sizeof(TYPENOTFALLBACK_TABLE) );
  514. if (!g_pNotFallBackTable)
  515. {
  516. LocalFree( TempDir );
  517. LocalFree( Directories );
  518. return FALSE;
  519. }
  520. g_nNotFallBack=0;
  521. Directory = Directories;
  522. //
  523. // Create NoFallBack Table
  524. //
  525. while (*Directory)
  526. {
  527. if (!GetPrivateProfileString( MUI_NOFALLBACK_SECTION,
  528. Directory,
  529. TEXT(""),
  530. TempDir,
  531. MAX_PATH,
  532. g_szMUIInfoFilePath))
  533. {
  534. LocalFree(g_pNotFallBackTable);
  535. LocalFree( TempDir );
  536. LocalFree( Directories );
  537. return FALSE;
  538. }
  539. //
  540. //
  541. //
  542. lpszNext=TempDir;
  543. nIdx=0;
  544. g_pNotFallBackTable[g_nNotFallBack].szSource[0]=TEXT('\0');
  545. while ( (*lpszNext != TEXT('\0')) && (*lpszNext != TEXT(',')) && (*lpszNext != TEXT(' ')) )
  546. {
  547. g_pNotFallBackTable[g_nNotFallBack].szSource[nIdx++]=*lpszNext;
  548. lpszNext++;
  549. }
  550. g_pNotFallBackTable[g_nNotFallBack].szSource[nIdx]=TEXT('\0');
  551. g_nNotFallBack++;
  552. while (*Directory++)
  553. {
  554. }
  555. }
  556. LocalFree( TempDir );
  557. LocalFree( Directories );
  558. return TRUE;
  559. }
  560. //
  561. // Check if a given file should be renamed by searching Rename Table
  562. //
  563. BOOL IsFileBeRenamed(LPTSTR lpszSrc,LPTSTR lpszDest)
  564. {
  565. int nIdx;
  566. BOOL bResult=FALSE;
  567. if (!lpszSrc)
  568. return bResult;
  569. for (nIdx=0; nIdx < g_nFileRename; nIdx++)
  570. {
  571. LPTSTR pMUI = StrStrI(lpszSrc,g_pFileRenameTable[nIdx].szSource);
  572. if (pMUI == lpszSrc)
  573. {
  574. pMUI += lstrlen(g_pFileRenameTable[nIdx].szSource);
  575. if (!*pMUI || !lstrcmpi(pMUI, TEXT(".MUI")))
  576. {
  577. lstrcpy(lpszDest,g_pFileRenameTable[nIdx].szDest);
  578. lstrcat(lpszDest, pMUI);
  579. bResult=TRUE;
  580. break;
  581. }
  582. }
  583. }
  584. return bResult;
  585. }
  586. //
  587. // Check if the file type of a given file belongs to the category "Do not Fallback"
  588. //
  589. BOOL IsDoNotFallBack(LPTSTR lpszFileName)
  590. {
  591. BOOL bResult = FALSE;
  592. int iLen,nIdx;
  593. iLen = _tcslen(lpszFileName);
  594. if (iLen > 4)
  595. {
  596. for (nIdx=0; nIdx < g_nNotFallBack ; nIdx++)
  597. {
  598. if (!_tcsicmp(&lpszFileName[iLen - 4],g_pNotFallBackTable[nIdx].szSource))
  599. {
  600. bResult = TRUE;
  601. break;
  602. }
  603. }
  604. }
  605. return bResult;
  606. }
  607. ////////////////////////////////////////////////////////////////////////////////////
  608. //
  609. // Muisetup_CheckForExpandedFile
  610. //
  611. // Retreives the original filename, in case the file is compressed.
  612. //
  613. ////////////////////////////////////////////////////////////////////////////////////
  614. BOOL Muisetup_CheckForExpandedFile(
  615. PTSTR pszPathName,
  616. PTSTR pszFileName,
  617. PTSTR pszOriginalFileName,
  618. PDIAMOND_PACKET pDiamond)
  619. {
  620. TCHAR szCompressedFileName[ MAX_PATH ];
  621. TCHAR szOut[ MAX_PATH ];
  622. PTSTR pszTemp, pszDelimiter;
  623. BOOL bIsCompressed;
  624. int iLen=0;
  625. // Initializations
  626. bIsCompressed = FALSE;
  627. szOut[ 0 ] = szCompressedFileName[ 0 ] = TEXT('\0');
  628. //
  629. // Get the real name
  630. //
  631. _tcscpy(szCompressedFileName, pszPathName);
  632. _tcscat(szCompressedFileName, pszFileName);
  633. if (Muisetup_IsDiamondFile( szCompressedFileName,
  634. pszOriginalFileName,
  635. MAX_PATH,
  636. pDiamond ))
  637. {
  638. return TRUE;
  639. }
  640. if (GetExpandedName(szCompressedFileName, szOut) == TRUE)
  641. {
  642. pszDelimiter = pszTemp = szOut;
  643. while (*pszTemp)
  644. {
  645. if ((*pszTemp == TEXT('\\')) ||
  646. (*pszTemp == TEXT('/')))
  647. {
  648. pszDelimiter = pszTemp;
  649. }
  650. pszTemp++;
  651. }
  652. if (*pszDelimiter == TEXT('\\') ||
  653. *pszDelimiter == TEXT('/'))
  654. {
  655. pszDelimiter++;
  656. }
  657. if (_tcsicmp(pszDelimiter, pszFileName) != 0)
  658. {
  659. bIsCompressed = TRUE;
  660. _tcscpy(pszOriginalFileName, pszDelimiter);
  661. }
  662. }
  663. if (!bIsCompressed)
  664. {
  665. _tcscpy(pszOriginalFileName, pszFileName);
  666. //
  667. // If muisetup is launched through [GUIRunOnce] command line mode,
  668. // W2K uncompresses all mui files and leave the name as xxxxxx.xxx.mu_
  669. // We should cover this situation by changing the name to xxxxxx.xxx.mui
  670. iLen = _tcslen(pszOriginalFileName);
  671. if (iLen > 4)
  672. {
  673. if (_tcsicmp(&pszOriginalFileName[iLen - 4], TEXT(".mu_")) == 0)
  674. {
  675. pszOriginalFileName[iLen-1]=TEXT('i');
  676. }
  677. }
  678. }
  679. return TRUE;
  680. }
  681. ////////////////////////////////////////////////////////////////////////////////////
  682. //
  683. // Muisetup_CopyFile
  684. //
  685. // Copy file, and expand it if necessary.
  686. //
  687. ////////////////////////////////////////////////////////////////////////////////////
  688. BOOL Muisetup_CopyFile(
  689. PCTSTR pszCopyFrom,
  690. PTSTR pszCopyTo,
  691. PDIAMOND_PACKET pDiamond,
  692. PTSTR pOriginalName)
  693. {
  694. OFSTRUCT ofs;
  695. INT hfFrom = -1, hfTo = -1;
  696. BOOL bRet = FALSE;
  697. //
  698. // Check if diamond can handle it
  699. //
  700. bRet = Muisetup_CopyDiamondFile( pDiamond,
  701. pszCopyTo );
  702. if (bRet)
  703. {
  704. //
  705. // Diamond copy won't rename file for us
  706. //
  707. if (pOriginalName)
  708. {
  709. WCHAR wszPath[MAX_PATH];
  710. //
  711. // Diamond is ANSI
  712. //
  713. if (MultiByteToWideChar(1252, 0, pDiamond->szDestFilePath, -1, wszPath, ARRAYSIZE(wszPath)))
  714. {
  715. StrCat(wszPath, pOriginalName);
  716. MoveFileEx(wszPath,pszCopyTo,MOVEFILE_REPLACE_EXISTING);
  717. }
  718. }
  719. return bRet;
  720. }
  721. hfFrom = LZOpenFile( (PTSTR) pszCopyFrom,
  722. &ofs,
  723. OF_READ );
  724. if (hfFrom < 0)
  725. {
  726. goto CopyFileRetry;
  727. }
  728. hfTo = LZOpenFile( (PTSTR) pszCopyTo,
  729. &ofs,
  730. OF_CREATE | OF_WRITE);
  731. if (hfTo < 0)
  732. {
  733. goto CopyFileRetry;
  734. }
  735. if (LZCopy(hfFrom, hfTo) < 0)
  736. {
  737. goto CopyFileRetry;
  738. }
  739. LZClose(hfFrom);
  740. LZClose(hfTo);
  741. return TRUE;
  742. CopyFileRetry:
  743. //
  744. // We may end up in a case where either the user uses directories with
  745. // path names > 128 characters(this will fail the LZ API's) or the LZ's
  746. // just fail. We just revert back to CopyFile and let the user deal
  747. // with that.
  748. //
  749. if(hfFrom >= 0) {
  750. LZClose(hfFrom);
  751. }
  752. if(hfTo >= 0) {
  753. LZClose(hfTo);
  754. }
  755. return CopyFile(pszCopyFrom, pszCopyTo, FALSE);
  756. }
  757. ////////////////////////////////////////////////////////////////////////////////////
  758. //
  759. // InstallComponentsMUIFiles
  760. //
  761. // Parameters:
  762. // pszLangSourceDir The sub-directory name for a specific lanuage in the MUI CD-ROM.
  763. // E.g. "jpn.MUI"
  764. // pszLanguage The LCID for the specific language. E.g. "0404".
  765. // isInstall TRUE if you are going to install the MUI files for the component. FALSE
  766. // if you are going to uninstall.
  767. // [OUT] pbCanceled TRUE if the operation is canceled.
  768. // [OUT] pbError TURE if error happens.
  769. //
  770. // Return:
  771. // TRUE if success. Otherwise FALSE.
  772. //
  773. // Note:
  774. // For the language resources stored in pszLangSourceDir, this function will enumerate
  775. // the compoents listed in the [Components]
  776. // (the real section is put in MUI_COMPONENTS_SECTION) section, and execute the INF file
  777. // listed in every entry in
  778. // the [Components] section.
  779. //
  780. ////////////////////////////////////////////////////////////////////////////////////
  781. BOOL InstallComponentsMUIFiles(PTSTR pszLangSourceDir, PTSTR pszLanguage, BOOL isInstall)
  782. {
  783. BOOL result = TRUE;
  784. TCHAR szComponentName[BUFFER_SIZE];
  785. TCHAR CompDir[BUFFER_SIZE];
  786. TCHAR CompINFFile[BUFFER_SIZE];
  787. TCHAR CompInstallSection[BUFFER_SIZE];
  788. TCHAR CompUninstallSection[BUFFER_SIZE];
  789. TCHAR szCompInfFullPath[MAX_PATH];
  790. LONG_PTR lppArgs[2];
  791. INFCONTEXT InfContext;
  792. TCHAR szBuffer[BUFFER_SIZE];
  793. HINF hInf = SetupOpenInfFile(g_szMUIInfoFilePath, NULL, INF_STYLE_WIN4, NULL);
  794. if (hInf == INVALID_HANDLE_VALUE)
  795. {
  796. _stprintf(szBuffer, TEXT("%d"), GetLastError());
  797. lppArgs[0] = (LONG_PTR)szBuffer;
  798. LogFormattedMessage(ghInstance, IDS_NO_READ_L, lppArgs);
  799. return (FALSE);
  800. }
  801. //
  802. // Get the first comopnent to be installed.
  803. //
  804. if (SetupFindFirstLine(hInf, MUI_COMPONENTS_SECTION, NULL, &InfContext))
  805. {
  806. do
  807. {
  808. if (!SetupGetStringField(&InfContext, 0, szComponentName, sizeof(szComponentName), NULL))
  809. {
  810. lppArgs[0]=(LONG_PTR)szComponentName;
  811. LogFormattedMessage(ghInstance, IDS_COMP_MISSING_NAME_L, lppArgs);
  812. continue;
  813. }
  814. if (!SetupGetStringField(&InfContext, 1, CompDir, sizeof(CompDir), NULL))
  815. {
  816. //
  817. // "LOG: MUI files for component %1 was not installed because of missing component direcotry.\n"
  818. //
  819. lppArgs[0]=(LONG_PTR)szComponentName;
  820. LogFormattedMessage(ghInstance, IDS_COMP_MISSING_DIR_L, lppArgs);
  821. continue;
  822. }
  823. if (!SetupGetStringField(&InfContext, 2, CompINFFile, sizeof(CompINFFile), NULL))
  824. {
  825. //
  826. // "LOG: MUI files for component %1 were not installed because of missing component INF filename.\n"
  827. //
  828. lppArgs[0]=(LONG_PTR)szComponentName;
  829. LogFormattedMessage(ghInstance, IDS_COMP_MISSING_INF_L, lppArgs);
  830. continue;
  831. }
  832. if (!SetupGetStringField(&InfContext, 3, CompInstallSection, sizeof(CompInstallSection), NULL))
  833. {
  834. _tcscpy(CompInstallSection, DEFAULT_INSTALL_SECTION);
  835. }
  836. if (!SetupGetStringField(&InfContext, 4, CompUninstallSection, sizeof(CompUninstallSection), NULL))
  837. {
  838. _tcscpy(CompUninstallSection, DEFAULT_UNINSTALL_SECTION);
  839. }
  840. //
  841. // Establish the correct path for component INF file.
  842. //
  843. if (isInstall)
  844. {
  845. //
  846. // For installation, we execute the INFs in the language directory of the CD-ROM (e.g.
  847. // g:\jpn.mui\i386\ie5\ie5ui.inf
  848. //
  849. _stprintf(szCompInfFullPath, TEXT("%s%s\\%s%s\\%s"),
  850. g_szMUISetupFolder,
  851. pszLangSourceDir,
  852. g_szPlatformPath,
  853. CompDir, CompINFFile);
  854. if (!ExecuteComponentINF(NULL, szComponentName, szCompInfFullPath, CompInstallSection, TRUE))
  855. {
  856. if (DoMessageBox(NULL, IDS_CANCEL_INSTALLATION, IDS_MAIN_TITLE, MB_YESNO) == IDNO)
  857. {
  858. result = FALSE;
  859. break;
  860. }
  861. }
  862. } else
  863. {
  864. //
  865. // For uninstallation, we execute the INFs in the \winnt\mui\fallback directory to remove component files.
  866. //
  867. _stprintf(szCompInfFullPath, TEXT("%s%s\\%s\\%s"), g_szWinDir, FALLBACKDIR, pszLanguage, CompINFFile) ;
  868. if (!ExecuteComponentINF(NULL, szComponentName, szCompInfFullPath, CompUninstallSection, FALSE) && result)
  869. {
  870. result = FALSE;
  871. }
  872. }
  873. //
  874. // Install the next component.
  875. //
  876. } while (SetupFindNextLine(&InfContext, &InfContext));
  877. }
  878. SetupCloseInfFile(hInf);
  879. return (result);
  880. }
  881. ////////////////////////////////////////////////////////////////////////////////////
  882. //
  883. // CopyFiles
  884. //
  885. // Copies the specified files to the appropriate directories
  886. //
  887. // Parameters:
  888. // [in] languages: contain the hex string for the languages to be installed. There could be more than one language.
  889. // [out] lpbCopyCancelled: if the copy operation has been cancelled.
  890. //
  891. // Notes:
  892. // This function first look at the [Languages] section in the INF file to find out the
  893. // source directory (in the CD-ROM) for the language to be installed.
  894. // From that directory, do:
  895. // 1. install the MUI files for the components listed in the [Components] section,
  896. // 2. Enumarate every file in that direcotry to:
  897. // Check if the same file exists in directories in DirNames. If yes, this means we have to copy
  898. // the mui file to that particular direcotry. Otherwise, copy the file to the FALLBACK directory.
  899. //
  900. ////////////////////////////////////////////////////////////////////////////////////
  901. BOOL CopyFiles(HWND hWnd, LPTSTR Languages)
  902. {
  903. LPTSTR Language;
  904. HANDLE hFile;
  905. HWND hStatic;
  906. TCHAR lpStatus[ BUFFER_SIZE ];
  907. TCHAR lpLangText[ BUFFER_SIZE ];
  908. TCHAR szSource[ MAX_PATH ] = {0}; // The source directory for a particular language
  909. TCHAR szTarget[ MAX_PATH ];
  910. TCHAR szTemp[ MAX_PATH ];
  911. TCHAR szOriginalFileName[ MAX_PATH ];
  912. TCHAR szFileNameBeforeRenamed[ MAX_PATH], szFileNameCopied[MAX_PATH];
  913. TCHAR szFileRenamed[MAX_PATH];
  914. DIAMOND_PACKET diamond;
  915. BOOL CreateFailure = FALSE;
  916. BOOL CopyOK=TRUE;
  917. BOOL bFileWithNoMuiExt=FALSE;
  918. BOOL FileCopied = FALSE;
  919. BOOL bSpecialDirectory=FALSE;
  920. BOOL bRename=FALSE;
  921. WIN32_FIND_DATA FindFileData;
  922. int FoundMore = 1;
  923. int Dirnum = 0;
  924. int iLen;
  925. int NotDeleted = 0;
  926. int i;
  927. TCHAR dir[_MAX_DIR];
  928. TCHAR fname[_MAX_FNAME];
  929. TCHAR ext[_MAX_EXT];
  930. LONG_PTR lppArgs[1];
  931. MSG msg;
  932. //
  933. // we need to try to copy for each language to be installed the file
  934. //
  935. hStatic = GetDlgItem(ghProgDialog, IDC_STATUS);
  936. Language = Languages;
  937. while (*Language)
  938. {
  939. //
  940. // Find the directory in which the sourcefile for given language should be
  941. //
  942. GetPrivateProfileString( MUI_LANGUAGES_SECTION,
  943. Language,
  944. TEXT("DEFAULT"),
  945. szSource,
  946. (sizeof(szSource)/sizeof(TCHAR)),
  947. g_szMUIInfoFilePath );
  948. //
  949. // Install Fusion MUI assemblies
  950. //
  951. if (gpfnSxsInstallW)
  952. {
  953. TCHAR pszLogFile[BUFFER_SIZE];
  954. if ( !DeleteSideBySideMUIAssemblyIfExisted(Language, pszLogFile))
  955. {
  956. TCHAR errInfo[BUFFER_SIZE];
  957. swprintf(errInfo, TEXT("Uninstall existing assemblies based on %s before new installation failed\n"), pszLogFile);
  958. OutputDebugString(errInfo);
  959. }
  960. if (GetFileAttributes(pszLogFile) != 0xFFFFFFFF)
  961. {
  962. DeleteFile(pszLogFile); // no use anyway
  963. }
  964. TCHAR szFusionAssemblyPath[BUFFER_SIZE];
  965. PathCombine(szFusionAssemblyPath, g_szMUISetupFolder, szSource);
  966. PathAppend(szFusionAssemblyPath, g_szPlatformPath);
  967. PathAppend(szFusionAssemblyPath, TEXT("ASMS"));
  968. SXS_INSTALLW SxsInstallInfo = {sizeof(SxsInstallInfo)};
  969. SXS_INSTALL_REFERENCEW Reference = {sizeof(Reference)};
  970. Reference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_OPAQUESTRING;
  971. Reference.lpIdentifier = MUISETUP_ASSEMBLY_INSTALLATION_REFERENCE_IDENTIFIER;
  972. SxsInstallInfo.dwFlags = SXS_INSTALL_FLAG_REPLACE_EXISTING |
  973. SXS_INSTALL_FLAG_REFERENCE_VALID |
  974. SXS_INSTALL_FLAG_CODEBASE_URL_VALID |
  975. SXS_INSTALL_FLAG_LOG_FILE_NAME_VALID |
  976. SXS_INSTALL_ASSEMBLY_FLAG_FROM_DIRECTORY_RECURSIVE;
  977. SxsInstallInfo.lpReference = &Reference;
  978. SxsInstallInfo.lpLogFileName = pszLogFile;
  979. SxsInstallInfo.lpManifestPath = szFusionAssemblyPath;
  980. SxsInstallInfo.lpCodebaseURL = SxsInstallInfo.lpManifestPath;
  981. if ( !gpfnSxsInstallW(&SxsInstallInfo))
  982. {
  983. TCHAR errInfo[BUFFER_SIZE];
  984. swprintf(errInfo, TEXT("Assembly Installation of %s failed. Please refer Eventlog for more information"), szFusionAssemblyPath);
  985. OutputDebugString(errInfo);
  986. }
  987. }
  988. GetLanguageGroupDisplayName((LANGID)_tcstol(Language, NULL, 16), lpLangText, ARRAYSIZE(lpLangText)-1);
  989. lppArgs[0] = (LONG_PTR)lpLangText;
  990. //
  991. // Try installing component satellite DLLs
  992. //
  993. FormatStringFromResource(lpStatus, sizeof(lpStatus)/sizeof(TCHAR), ghInstance, IDS_INSTALLING_COMP_MUI, lppArgs);
  994. SetWindowText(hStatic, lpStatus);
  995. if (!InstallComponentsMUIFiles(szSource, NULL, TRUE))
  996. {
  997. #ifndef IGNORE_COPY_ERRORS
  998. DeleteFiles(Languages,&NotDeleted);
  999. return FALSE;
  1000. #endif
  1001. }
  1002. //
  1003. // Output what is being installed on the progress dialog box
  1004. //
  1005. LoadString(ghInstance, IDS_INSTALLING, lpStatus, ARRAYSIZE(lpStatus)-1);
  1006. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1007. lpStatus,
  1008. 0,
  1009. 0,
  1010. lpStatus,
  1011. ARRAYSIZE(lpStatus)-1,
  1012. (va_list *)lppArgs);
  1013. SetWindowText(hStatic, lpStatus);
  1014. //
  1015. // find first file in language subdirectory
  1016. //
  1017. _tcscpy(szTemp,szSource);
  1018. // szSource = g_szMUISetupFolder\szSource\tchPlatfromPath
  1019. // e.g. szSource = "g_szMUISetupFolder\JPN.MUI\i386\"
  1020. _tcscpy(szSource,g_szMUISetupFolder);
  1021. _tcscat(szSource,szTemp);
  1022. _tcscat(szSource, TEXT("\\"));
  1023. _tcscat(szSource, g_szPlatformPath); // i386 or alpha
  1024. // szTemp = szSource + "*.*"
  1025. // e.g. szTemp = "g_szMUISetupFolder\JPN.MUI\i386\*.*"
  1026. _tcscpy(szTemp,szSource);
  1027. _tcscat(szTemp,TEXT("*.*"));
  1028. FoundMore = 1; // reset foundmore for next language.
  1029. hFile = FindFirstFile( szTemp, &FindFileData );
  1030. if (INVALID_HANDLE_VALUE == hFile)
  1031. return FALSE;
  1032. _tcscpy(szTemp, TEXT(""));
  1033. while (FoundMore)
  1034. {
  1035. CreateFailure=FALSE;
  1036. FileCopied=FALSE;
  1037. if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  1038. {
  1039. //
  1040. // Reset diamond stuff for the new file
  1041. //
  1042. Muisetup_DiamondReset(&diamond);
  1043. //
  1044. // Check if it's a compressed file or not
  1045. //
  1046. Muisetup_CheckForExpandedFile( szSource,
  1047. FindFileData.cFileName,
  1048. szOriginalFileName,
  1049. &diamond );
  1050. if (IsFileBeRenamed(szOriginalFileName,szFileRenamed))
  1051. {
  1052. _tcscpy(szFileNameBeforeRenamed,szOriginalFileName);
  1053. _tcscpy(szOriginalFileName,szFileRenamed);
  1054. bRename=TRUE;
  1055. }
  1056. else
  1057. {
  1058. bRename=FALSE;
  1059. }
  1060. // e.g. szTemp = "shell32.dll"
  1061. _tcscpy(szTemp, szOriginalFileName); //////////////
  1062. FileCopied=FALSE;
  1063. for (Dirnum=1; (_tcslen(DirNames[Dirnum])>0); Dirnum++ )
  1064. {
  1065. //
  1066. // see where this file has to go
  1067. //
  1068. pfnGetWindowsDir( szTarget, MAX_PATH);
  1069. // e.g. szTarget = "c:\winnt\system32\wbem"
  1070. _tcscat(szTarget, DirNames[Dirnum]);
  1071. if (_tcscmp(DirNames[Dirnum], TEXT("\\")))
  1072. {
  1073. _tcscat(szTarget, TEXT("\\"));
  1074. }
  1075. bFileWithNoMuiExt = FALSE;
  1076. _tcscpy(szTemp, szOriginalFileName); //remove .mui if it's .mui ////////
  1077. iLen = _tcslen(szTemp);
  1078. if (iLen > 4)
  1079. {
  1080. if (_tcsicmp(&szTemp[iLen - 4], TEXT(".mui")) == 0)
  1081. {
  1082. *(szTemp + iLen - 4) = 0;
  1083. }
  1084. else
  1085. {
  1086. bFileWithNoMuiExt = TRUE;
  1087. }
  1088. }
  1089. _tcscat(szTarget, szTemp);
  1090. //
  1091. // Check the file with the same name (with the .mui extension) exist in the
  1092. // system directory. If yes, this means that we need to copy the mui file.
  1093. //
  1094. if (FileExists(szTarget))
  1095. {
  1096. //
  1097. // need to copy this file to the directory
  1098. //
  1099. FileCopied = TRUE;
  1100. //
  1101. // copy filename in szTemp and directory in szTarget
  1102. //
  1103. _tsplitpath( szTarget, szTemp, dir, fname, ext );
  1104. _tcscpy(szTarget, szTemp); // drive name
  1105. _tcscat(szTarget, dir); // directory name
  1106. //
  1107. //now szTarget = Directory, szTemp = filename
  1108. //
  1109. _tcscat(szTarget, MUIDIR); // append MUI to directory
  1110. if (!MakeDir(szTarget)) // if the MUI dir doesn't exist yet, create it.
  1111. {
  1112. MakeDirFailed(szTarget);
  1113. CreateFailure = TRUE;
  1114. }
  1115. _tcscat(szTarget, TEXT("\\"));
  1116. _tcscat(szTarget, Language); // add Language Identifier (from MUI.INF, e.g., 0407)
  1117. if (!FileExists(szTarget)) // if the directory doesn't exist yet
  1118. {
  1119. if (!MakeDir(szTarget)) // if the LANGID dir doesn't exist yet, create it.
  1120. {
  1121. MakeDirFailed(szTarget);
  1122. CreateFailure=TRUE;
  1123. }
  1124. }
  1125. _tcscat(szTarget, TEXT("\\")); // append \ /
  1126. if (bRename)
  1127. {
  1128. _tcscpy(szFileNameCopied,szTarget);
  1129. _tcscat(szFileNameCopied,szFileNameBeforeRenamed);
  1130. }
  1131. _tcscat(szTarget, szOriginalFileName); // append filename
  1132. _tcscpy(szTemp, szSource);
  1133. _tcscat(szTemp, FindFileData.cFileName);
  1134. if (!CreateFailure)
  1135. {
  1136. if (!Muisetup_CopyFile(szTemp, szTarget, &diamond, bRename? szFileNameBeforeRenamed:NULL))
  1137. {
  1138. CopyFileFailed(szTarget,0);
  1139. CreateFailure = TRUE;
  1140. CopyOK = FALSE;
  1141. }
  1142. else
  1143. {
  1144. SendMessage(ghProgress, PBM_DELTAPOS, (WPARAM)(1), 0);
  1145. //
  1146. // Diamond decompression doesn't rename correctly
  1147. //
  1148. /*
  1149. if (bRename)
  1150. {
  1151. MoveFileEx(szFileNameCopied,szTarget,MOVEFILE_REPLACE_EXISTING);
  1152. }
  1153. */
  1154. }
  1155. }
  1156. } // if fileexists
  1157. } // of for
  1158. //
  1159. // the file was not found in any of the known MUI targets -> fallback.
  1160. // Simple hack for FAXUI.DLL to be copied to the fallback directory as well.
  1161. //
  1162. bSpecialDirectory=FALSE;
  1163. for (i = 0; i < ARRAYSIZE(g_szSpecialFiles); i++)
  1164. {
  1165. if (_tcsicmp(szOriginalFileName, g_szSpecialFiles[i]) == 0)
  1166. {
  1167. bSpecialDirectory=TRUE;
  1168. }
  1169. }
  1170. if ( ( (FileCopied != TRUE) && (!IsDoNotFallBack(szOriginalFileName))) ||
  1171. (_tcsicmp(szOriginalFileName, TEXT("faxui.dll.mui")) == 0) )
  1172. {
  1173. pfnGetWindowsDir(szTarget, MAX_PATH); //%windir% //
  1174. _tcscat(szTarget, TEXT("\\"));
  1175. //
  1176. // If the file couldn't be found in any of the above, and it's extension
  1177. // doesn't contain .mui, then copy it to %windir%\system32
  1178. // szTemp holds the filename.
  1179. //
  1180. if (bSpecialDirectory)
  1181. {
  1182. // e.g. szTarget = "c:\winnt\system32\";
  1183. _tcscat(szTarget, TEXT("system32\\"));
  1184. }
  1185. // e.g. szTarget = "c:\winnt\system32\MUI" (when bSpecialDirectory = TRUE) or "c:\winnt\MUI"
  1186. _tcscat(szTarget, MUIDIR); // \MUI //
  1187. if (!MakeDir(szTarget)) // if the MUI dir doesn't exist yet, create it.
  1188. {
  1189. MakeDirFailed(szTarget);
  1190. CreateFailure = TRUE;
  1191. }
  1192. if (!bSpecialDirectory)
  1193. {
  1194. // e.g. szTarget = "C:\winnt\MUI\FALLBACK"
  1195. _tcscat(szTarget, TEXT("\\"));
  1196. _tcscat(szTarget, TEXT("FALLBACK")); // FALLBACK
  1197. if (!MakeDir(szTarget)) // if the MUI dir doesn't exist yet, create it.
  1198. {
  1199. MakeDirFailed(szTarget);
  1200. CreateFailure = TRUE;
  1201. }
  1202. }
  1203. _tcscat(szTarget, TEXT("\\")); // \ //
  1204. // e.g. szTarget = "c:\winnt\system32\MUI\0411" (when bSpecialDirectory = TRUE) or "c:\winnt\MUI\FALLBACK\0411"
  1205. _tcscat(szTarget, Language); // add Language Identifier (from MUI.INF, e.g., 0407)
  1206. if (!MakeDir(szTarget)) // if the MUI dir doesn't exist yet, create it.
  1207. {
  1208. MakeDirFailed(szTarget);
  1209. CreateFailure = TRUE;
  1210. }
  1211. _tcscat(szTarget, TEXT("\\")); // \ //
  1212. _tcscat(szTarget, szOriginalFileName); // filename
  1213. _tcscpy(szTemp, szSource);
  1214. _tcscat(szTemp, FindFileData.cFileName);
  1215. if (!CreateFailure)
  1216. {
  1217. if (!Muisetup_CopyFile(szTemp, szTarget, &diamond, bRename? szFileNameBeforeRenamed:NULL))
  1218. {
  1219. CopyFileFailed(szTarget,0);
  1220. CopyOK = FALSE;
  1221. }
  1222. else
  1223. {
  1224. SendMessage(ghProgress, PBM_DELTAPOS, (WPARAM)(1), 0);
  1225. }
  1226. }
  1227. if (CreateFailure == TRUE)
  1228. {
  1229. CopyOK=FALSE;
  1230. }
  1231. } // fallback case
  1232. } // of file not dir
  1233. FoundMore = FindNextFile( hFile, &FindFileData );
  1234. //
  1235. // Since this is a lengthy operation, we should
  1236. // peek and dispatch window messages here so
  1237. // that MUISetup dialog could repaint itself.
  1238. //
  1239. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1240. {
  1241. if (msg.message == WM_QUIT)
  1242. {
  1243. return (FALSE);
  1244. }
  1245. TranslateMessage(&msg);
  1246. DispatchMessage(&msg);
  1247. }
  1248. } // of while
  1249. FindClose(hFile);
  1250. lppArgs[0] = (LONG_PTR)Language;
  1251. LogFormattedMessage(NULL, IDS_LANG_INSTALLED, lppArgs);
  1252. while (*Language++) // go to the next language and repeat
  1253. {
  1254. }
  1255. } // of while (*Language)
  1256. #ifndef IGNORE_COPY_ERRORS
  1257. if (!CopyOK)
  1258. {
  1259. if (DoMessageBox(NULL, IDS_CANCEL_INSTALLATION, IDS_MAIN_TITLE, MB_YESNO) == IDNO)
  1260. {
  1261. DeleteFiles(Languages,&NotDeleted);
  1262. }
  1263. else
  1264. {
  1265. CopyOK = TRUE;
  1266. }
  1267. }
  1268. #endif
  1269. return CopyOK;
  1270. }
  1271. ////////////////////////////////////////////////////////////////////////////////////
  1272. //
  1273. // Copy or remove muisetup related files
  1274. // Help file : %windir%\help
  1275. // Other files : %windir%\mui
  1276. //
  1277. ////////////////////////////////////////////////////////////////////////////////////
  1278. BOOL CopyRemoveMuiItself(BOOL bInstall)
  1279. {
  1280. //
  1281. // MUISETUP files need to be copied from MUI CD
  1282. //
  1283. TCHAR *TargetFiles[] = {
  1284. TEXT("muisetup.exe"),
  1285. TEXT("mui.inf"),
  1286. TEXT("eula.txt"),
  1287. TEXT("readme.txt"),
  1288. TEXT("relnotes.txt")
  1289. };
  1290. TCHAR szTargetPath[MAX_PATH+1], szTargetFile[MAX_PATH+1];
  1291. TCHAR szSrcFile[MAX_PATH+1];
  1292. TCHAR szHelpFile[MAX_PATH+1];
  1293. BOOL bRet = FALSE;
  1294. int i;
  1295. PathCombine(szTargetPath, g_szWinDir, MUIDIR);
  1296. if (MakeDir(szTargetPath))
  1297. {
  1298. //
  1299. // Copy over MUISETUP related files
  1300. //
  1301. for (i=0; i<ARRAYSIZE(TargetFiles); i++)
  1302. {
  1303. PathCombine(szTargetFile, szTargetPath, TargetFiles[i]);
  1304. PathCombine(szSrcFile, g_szMUISetupFolder, TargetFiles[i]);
  1305. if (bInstall)
  1306. {
  1307. RemoveFileReadOnlyAttribute(szTargetFile);
  1308. CopyFile(szSrcFile,szTargetFile,FALSE);
  1309. RemoveFileReadOnlyAttribute(szTargetFile);
  1310. }
  1311. else
  1312. {
  1313. if (FileExists(szTargetFile) &&
  1314. !MUI_DeleteFile(szTargetFile))
  1315. {
  1316. MoveFileEx(szTargetFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  1317. }
  1318. }
  1319. }
  1320. //
  1321. // Copy over muisetup help file
  1322. //
  1323. LoadString(NULL, IDS_HELPFILE,szHelpFile,MAX_PATH);
  1324. PathCombine(szTargetFile, g_szWinDir, HELPDIR);
  1325. PathAppend(szTargetFile, szHelpFile);
  1326. PathCombine(szSrcFile, g_szMUISetupFolder, szHelpFile);
  1327. if (bInstall)
  1328. {
  1329. RemoveFileReadOnlyAttribute(szTargetFile);
  1330. CopyFile(szSrcFile,szTargetFile,FALSE);
  1331. RemoveFileReadOnlyAttribute(szTargetFile);
  1332. }
  1333. else
  1334. {
  1335. if (FileExists(szTargetFile) &&
  1336. !MUI_DeleteFile(szTargetFile))
  1337. {
  1338. MoveFileEx(szTargetFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  1339. }
  1340. }
  1341. bRet = TRUE;
  1342. }
  1343. return bRet;
  1344. }
  1345. BOOL IsAllLanguageRemoved(LPTSTR Language)
  1346. {
  1347. int mask[MAX_UI_LANG_GROUPS],nIdx;
  1348. LCID SystemUILangId,lgCheck;
  1349. BOOL bResult=FALSE;
  1350. if (gNumLanguages_Install > 0)
  1351. return bResult;
  1352. SystemUILangId=(LCID) gSystemUILangId;
  1353. for ( nIdx=0; nIdx<g_UILanguageGroup.iCount;nIdx++)
  1354. {
  1355. if ( gSystemUILangId == g_UILanguageGroup.lcid[nIdx])
  1356. {
  1357. mask[nIdx]=1;
  1358. }
  1359. else
  1360. {
  1361. mask[nIdx]=0;
  1362. }
  1363. }
  1364. while (*Language)
  1365. {
  1366. lgCheck = (LCID)_tcstol(Language,NULL,16);
  1367. for ( nIdx=0; nIdx<g_UILanguageGroup.iCount;nIdx++)
  1368. {
  1369. if ( lgCheck == g_UILanguageGroup.lcid[nIdx])
  1370. {
  1371. mask[nIdx]=1;
  1372. break;
  1373. }
  1374. }
  1375. while (*Language++)
  1376. {
  1377. }
  1378. }
  1379. bResult=TRUE;
  1380. for ( nIdx=0; nIdx<g_UILanguageGroup.iCount;nIdx++)
  1381. {
  1382. if ( mask[nIdx] == 0)
  1383. {
  1384. bResult = FALSE;
  1385. break;
  1386. }
  1387. }
  1388. return bResult;
  1389. }
  1390. void DoRemoveFiles(LPTSTR szDirToDelete, int* pnNotDeleted)
  1391. {
  1392. // File wildcard pattern.
  1393. TCHAR szTarget[MAX_PATH];
  1394. // File to be deleted.
  1395. TCHAR szFileName[MAX_PATH];
  1396. // Sub-directory name
  1397. TCHAR szSubDirName[MAX_PATH];
  1398. int FoundMore = 1;
  1399. HANDLE hFile;
  1400. WIN32_FIND_DATA FindFileData;
  1401. MSG msg;
  1402. // e.g. szTarget = "c:\winnt\system32\Wbem\MUI\0404\*.*"
  1403. _stprintf(szTarget, TEXT("%s\\*.*"), szDirToDelete);
  1404. hFile = FindFirstFile(szTarget, &FindFileData);
  1405. while (FoundMore)
  1406. {
  1407. if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  1408. {
  1409. _tcscpy(szFileName, szDirToDelete);
  1410. _tcscat(szFileName, TEXT("\\"));
  1411. _tcscat(szFileName, FindFileData.cFileName);
  1412. if (FileExists(szFileName))
  1413. {
  1414. // We should check if the said file is actually deleted
  1415. // If it's not the case, then we should post a defered deletion
  1416. //
  1417. if (!MUI_DeleteFile(szFileName))
  1418. {
  1419. (*pnNotDeleted)++;
  1420. MoveFileEx(szFileName, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  1421. }
  1422. }
  1423. SendMessage(ghProgress, PBM_DELTAPOS, (WPARAM)(1), 0);
  1424. } else
  1425. {
  1426. if (_tcscmp(FindFileData.cFileName, TEXT(".")) != 0 && _tcscmp(FindFileData.cFileName, TEXT("..")) != 0)
  1427. {
  1428. _stprintf(szSubDirName, TEXT("%s\\%s"), szDirToDelete, FindFileData.cFileName);
  1429. DoRemoveFiles(szSubDirName, pnNotDeleted);
  1430. }
  1431. }
  1432. //
  1433. // Since this is a lengthy operation, we should
  1434. // peek and dispatch window messages here so
  1435. // that MUISetup dialog could repaint itself.
  1436. //
  1437. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1438. {
  1439. if (msg.message == WM_QUIT)
  1440. {
  1441. return;
  1442. }
  1443. TranslateMessage(&msg);
  1444. DispatchMessage(&msg);
  1445. }
  1446. FoundMore = FindNextFile( hFile, &FindFileData );
  1447. }
  1448. FindClose(hFile);
  1449. //
  1450. // If the directory is not empty, then we should post a defered deletion
  1451. // for the directory
  1452. //
  1453. if (!RemoveDirectory(szDirToDelete))
  1454. {
  1455. MoveFileEx(szDirToDelete, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  1456. }
  1457. }
  1458. ////////////////////////////////////////////////////////////////////////////////////
  1459. //
  1460. // DeleteFiles
  1461. //
  1462. // Deletes MUI files for the languages specified
  1463. //
  1464. // Parameters:
  1465. // [IN] Languages: a double-null terminated string which contains languages
  1466. // to be processed.
  1467. // [OUT] lpNotDeleted: The number of files to be deleted after reboot.
  1468. //
  1469. ////////////////////////////////////////////////////////////////////////////////////
  1470. BOOL DeleteFiles(LPTSTR Languages, int *lpNotDeleted)
  1471. {
  1472. LPTSTR Language,Langchk;
  1473. HANDLE hFile;
  1474. HWND hStatic;
  1475. TCHAR lpLangText[BUFFER_SIZE];
  1476. TCHAR lpStatus[BUFFER_SIZE];
  1477. TCHAR szTarget[MAX_PATH];
  1478. TCHAR szMuiDir[MAX_PATH];
  1479. TCHAR szFallbackDir[MAX_PATH];
  1480. BOOL CreateFailure=FALSE;
  1481. int Dirnum = 0;
  1482. LONG_PTR lppArgs[3];
  1483. int i;
  1484. hStatic = GetDlgItem(ghProgDialog, IDC_STATUS);
  1485. Language = Langchk = Languages;
  1486. *lpNotDeleted = 0;
  1487. while (*Language)
  1488. {
  1489. GetLanguageGroupDisplayName((LANGID)_tcstol(Language, NULL, 16), lpLangText, ARRAYSIZE(lpLangText)-1);
  1490. lppArgs[0]= (LONG_PTR)lpLangText;
  1491. //
  1492. //
  1493. // Output what is being uninstalled on the progress dialog box
  1494. //
  1495. FormatStringFromResource(lpStatus, sizeof(lpStatus)/sizeof(TCHAR), ghInstance, IDS_UNINSTALLING, lppArgs);
  1496. SetWindowText(hStatic, lpStatus);
  1497. //
  1498. // Remove all files under special directories (those directories listed under [Directories] in mui.inf.
  1499. //
  1500. for (Dirnum=1; (_tcslen(DirNames[Dirnum])>0); Dirnum++ )
  1501. {
  1502. // szTarget = "c:\winnt"
  1503. _tcscpy(szTarget, g_szWinDir);
  1504. // e.g. szTarget = "c:\winnt\system32\Wbem"
  1505. _tcscat(szTarget, DirNames[Dirnum]);
  1506. if (_tcscmp(DirNames[Dirnum], TEXT("\\")))
  1507. {
  1508. // e.g. szTarget = "c:\winnt\system32\Wbem\"
  1509. _tcscat(szTarget, TEXT("\\"));
  1510. }
  1511. // e.g. szTarget = "c:\winnt\system32\Wbem\MUI"
  1512. _tcscat(szTarget, MUIDIR);
  1513. // e.g. szTarget = "c:\winnt\system32\Wbem\MUI\0404"
  1514. _tcscat(szTarget, TEXT("\\"));
  1515. _tcscat(szTarget, Language);
  1516. DoRemoveFiles(szTarget, lpNotDeleted);
  1517. }
  1518. // Uninstall Component MUI Files.
  1519. // Note that we should do this before removing all files under FALLBACK directory,
  1520. // since we store compoent INF files under the FALLBACK directory.
  1521. InstallComponentsMUIFiles(NULL, Language, FALSE);
  1522. //
  1523. // Remove all files under FALLBACK directory.
  1524. //
  1525. // E.g. szTarget = "c:\winnt\mui"
  1526. _tcscpy(szTarget, g_szWinDir);
  1527. _tcscat(szTarget, TEXT("\\"));
  1528. _tcscat(szTarget, MUIDIR);
  1529. _tcscpy(szMuiDir, szTarget);
  1530. // E.g. szTarget = "c:\winnt\mui\FALLBACK"
  1531. _tcscat(szTarget, TEXT("\\"));
  1532. _tcscat(szTarget, TEXT("FALLBACK"));
  1533. _tcscpy(szFallbackDir, szTarget);
  1534. _tcscat(szTarget, TEXT("\\"));
  1535. // E.g. szTarget = "c:\winnt\mui\FALLBACK\0404"
  1536. _tcscat(szTarget, Language);
  1537. DoRemoveFiles(szTarget, lpNotDeleted);
  1538. //
  1539. // Remove files listed in g_szSpecialFiles
  1540. //
  1541. for (i = 0; i < ARRAYSIZE(g_szSpecialFiles); i++)
  1542. { // e.g. szTarget = "c:\winnt\system32\mui\0411\hhctrlui.dll"
  1543. wsprintf(szTarget, L"%s\\system32\\%s\\%s\\%s",
  1544. g_szWinDir,
  1545. MUIDIR,
  1546. Language,
  1547. g_szSpecialFiles[i]);
  1548. if (!MUI_DeleteFile(szTarget))
  1549. {
  1550. (*lpNotDeleted)++;
  1551. }
  1552. }
  1553. /*
  1554. // e.g. szTarget = "c:\winnt\system32\mui\0411"
  1555. wsprintf(szTarget, L"%s\\system32\\%s\\%s",
  1556. g_szWinDir,
  1557. MUIDIR,
  1558. Language);
  1559. DoRemoveFiles(szTarget, lpNotDeleted);
  1560. */
  1561. lppArgs[0] = (LONG_PTR)Language;
  1562. LogFormattedMessage(NULL, IDS_LANG_UNINSTALLED, lppArgs);
  1563. while (*Language++) // go to the next language and repeat
  1564. {
  1565. }
  1566. } // of while (*Language)
  1567. //
  1568. // Removes Fallback directory if all languages have been uninstalled.
  1569. //
  1570. if (!RemoveDirectory(szFallbackDir))
  1571. {
  1572. MoveFileEx(szFallbackDir, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  1573. }
  1574. //
  1575. // Removes MUI directory if all languages have been uninstalled and Fallback
  1576. // directory has been removed.
  1577. //
  1578. if (IsAllLanguageRemoved(Langchk))
  1579. {
  1580. CopyRemoveMuiItself(FALSE);
  1581. }
  1582. if (!RemoveDirectory(szMuiDir))
  1583. {
  1584. MoveFileEx(szMuiDir, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  1585. }
  1586. return TRUE;
  1587. }
  1588. BOOL CompareMuisetupVersion(LPTSTR pszSrc,LPTSTR pszTarget)
  1589. {
  1590. BOOL bResult=TRUE;
  1591. ULONG ulHandle,ulHandle1,ulBytes,ulBytes1;
  1592. PVOID pvoidBuffer=NULL,pvoidBuffer1=NULL;
  1593. VS_FIXEDFILEINFO *lpvsInfo,*lpvsInfo1;
  1594. UINT unLen;
  1595. if ( (!pszSrc) || (!pszTarget))
  1596. {
  1597. bResult = FALSE;
  1598. goto endcompare;
  1599. }
  1600. ulBytes = GetFileVersionInfoSize( pszSrc, &ulHandle );
  1601. if ( ulBytes == 0 )
  1602. goto endcompare;
  1603. ulBytes1 = GetFileVersionInfoSize( pszTarget,&ulHandle1 );
  1604. if ( ulBytes1 == 0 )
  1605. goto endcompare;
  1606. pvoidBuffer=LocalAlloc(LMEM_FIXED,ulBytes+1);
  1607. if (!pvoidBuffer)
  1608. goto endcompare;
  1609. pvoidBuffer1=LocalAlloc(LMEM_FIXED,ulBytes1+1);
  1610. if (!pvoidBuffer1)
  1611. goto endcompare;
  1612. if ( !GetFileVersionInfo( pszSrc, ulHandle, ulBytes, pvoidBuffer ) )
  1613. goto endcompare;
  1614. if ( !GetFileVersionInfo( pszTarget, ulHandle1, ulBytes1, pvoidBuffer1 ) )
  1615. goto endcompare;
  1616. // Get fixed info block
  1617. if ( !VerQueryValue( pvoidBuffer,_T("\\"),(LPVOID *)&lpvsInfo,&unLen ) )
  1618. goto endcompare;
  1619. if ( !VerQueryValue( pvoidBuffer1,_T("\\"),(LPVOID *)&lpvsInfo1,&unLen ) )
  1620. goto endcompare;
  1621. bResult = FALSE;
  1622. //
  1623. // We do nothing if major release version is different
  1624. //
  1625. // I.E We won't copy a new muisetup.exe over a old one if major release version of them are different
  1626. //
  1627. if ( (lpvsInfo->dwFileVersionMS == lpvsInfo1->dwFileVersionMS) &&
  1628. (lpvsInfo->dwFileVersionLS < lpvsInfo1->dwFileVersionLS))
  1629. {
  1630. bResult = TRUE;
  1631. }
  1632. endcompare:
  1633. if(pvoidBuffer)
  1634. LocalFree(pvoidBuffer);
  1635. if(pvoidBuffer1)
  1636. LocalFree(pvoidBuffer1);
  1637. return bResult;
  1638. }
  1639. ////////////////////////////////////////////////////////////////////////////////////
  1640. //
  1641. // MZStrLen
  1642. //
  1643. // Calculate the length of MULTI_SZ string
  1644. //
  1645. // the length is in bytes and includes extra terminal NULL, so the length >= 1 (TCHAR)
  1646. //
  1647. ////////////////////////////////////////////////////////////////////////////////////
  1648. UINT MZStrLen(LPTSTR lpszStr)
  1649. {
  1650. UINT i=0;
  1651. while (lpszStr && *lpszStr)
  1652. {
  1653. i += ((lstrlen(lpszStr)+1) * sizeof(TCHAR));
  1654. lpszStr += (lstrlen(lpszStr)+1);
  1655. }
  1656. //
  1657. // extra NULL
  1658. //
  1659. i += sizeof(TCHAR);
  1660. return i;
  1661. }
  1662. ////////////////////////////////////////////////////////////////////////////////////
  1663. //
  1664. // SetFontLinkValue
  1665. //
  1666. // Set necessary font link value into registry
  1667. //
  1668. // lpszLinkInfo = "Target","Link1","Link2",....
  1669. //
  1670. ////////////////////////////////////////////////////////////////////////////////////
  1671. BOOL SetFontLinkValue (LPTSTR lpszLinkInfo,BOOL *lpbFontLinkRegistryTouched)
  1672. {
  1673. const TCHAR szDeli[] = TEXT("\\\\");
  1674. TCHAR szStrBuf[FONTLINK_BUF_SIZE];
  1675. TCHAR szRegDataStr[FONTLINK_BUF_SIZE];
  1676. LPTSTR lpszDstStr,lpszSrcStr;
  1677. LPTSTR lpszFontName;
  1678. LPTSTR lpszTok;
  1679. DWORD dwType;
  1680. DWORD cbData;
  1681. HKEY hKey;
  1682. LONG rc;
  1683. BOOL bRet = FALSE;
  1684. lpszSrcStr = szStrBuf;
  1685. lpszTok = _tcstok(lpszLinkInfo,szDeli);
  1686. while (lpszTok)
  1687. {
  1688. lstrcpy(lpszSrcStr,lpszTok);
  1689. lpszSrcStr += (lstrlen(lpszTok) + 1);
  1690. lpszTok = _tcstok(NULL,szDeli);
  1691. }
  1692. *lpszSrcStr = TEXT('\0');
  1693. //
  1694. // first token is base font name
  1695. //
  1696. lpszSrcStr = lpszFontName = szStrBuf;
  1697. if (! *lpszFontName)
  1698. {
  1699. //
  1700. // there is no link info needs to be processed
  1701. //
  1702. bRet = FALSE;
  1703. goto Exit1;
  1704. }
  1705. //
  1706. // point to first linked font
  1707. //
  1708. lpszSrcStr += (lstrlen(lpszSrcStr) + 1);
  1709. if (! *lpszSrcStr)
  1710. {
  1711. //
  1712. // no linked font
  1713. //
  1714. bRet = FALSE;
  1715. goto Exit1;
  1716. }
  1717. rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  1718. TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink"),
  1719. 0L,
  1720. NULL,
  1721. REG_OPTION_NON_VOLATILE,
  1722. KEY_READ | KEY_WRITE,
  1723. NULL,
  1724. &hKey,
  1725. NULL);
  1726. if (rc != ERROR_SUCCESS)
  1727. {
  1728. bRet = FALSE;
  1729. goto Exit1;
  1730. }
  1731. cbData = sizeof(szRegDataStr);
  1732. rc = RegQueryValueEx(hKey,
  1733. lpszFontName,
  1734. NULL,
  1735. &dwType,
  1736. (LPBYTE) szRegDataStr,
  1737. &cbData);
  1738. if (rc != ERROR_SUCCESS)
  1739. {
  1740. //
  1741. // case 1, this font's font link hasn't been set yet, or something wrong in old value
  1742. //
  1743. lpszDstStr = lpszSrcStr;
  1744. }
  1745. else
  1746. {
  1747. //
  1748. // case 2, this font's font link list has been there
  1749. //
  1750. // we need check if new font is defined in font list or not.
  1751. //
  1752. while (*lpszSrcStr)
  1753. {
  1754. lpszDstStr = szRegDataStr;
  1755. while (*lpszDstStr)
  1756. {
  1757. if (lstrcmpi(lpszSrcStr,lpszDstStr) == 0)
  1758. {
  1759. break;
  1760. }
  1761. lpszDstStr += (lstrlen(lpszDstStr) + 1);
  1762. }
  1763. if (! *lpszDstStr)
  1764. {
  1765. //
  1766. // the font is not in original linke font list then
  1767. //
  1768. // append to end of list
  1769. //
  1770. //
  1771. // make sure this is a safe copy
  1772. //
  1773. if (lpszDstStr+(lstrlen(lpszSrcStr)+2) < szRegDataStr+FONTLINK_BUF_SIZE)
  1774. {
  1775. lstrcpy(lpszDstStr,lpszSrcStr);
  1776. lpszDstStr += (lstrlen(lpszDstStr) + 1);
  1777. *lpszDstStr = TEXT('\0');
  1778. }
  1779. }
  1780. lpszSrcStr += (lstrlen(lpszSrcStr) + 1);
  1781. }
  1782. lpszDstStr = szRegDataStr;
  1783. }
  1784. //
  1785. // in this step,lpszDstStr is new font link list
  1786. //
  1787. rc = RegSetValueEx( hKey,
  1788. lpszFontName,
  1789. 0L,
  1790. REG_MULTI_SZ,
  1791. (LPBYTE)lpszDstStr,
  1792. MZStrLen(lpszDstStr));
  1793. if (rc != ERROR_SUCCESS)
  1794. {
  1795. goto Exit2;
  1796. }
  1797. bRet = TRUE;
  1798. *lpbFontLinkRegistryTouched = TRUE;
  1799. Exit2:
  1800. RegCloseKey(hKey);
  1801. Exit1:
  1802. return bRet;
  1803. }
  1804. ////////////////////////////////////////////////////////////////////////////////////
  1805. //
  1806. // MofCompileLanguages
  1807. //
  1808. // Call the WBEM API to mofcompile the MFL's for each language
  1809. //
  1810. ////////////////////////////////////////////////////////////////////////////////////
  1811. BOOL MofCompileLanguages(LPTSTR Languages)
  1812. {
  1813. pfnMUI_InstallMFLFiles pfnMUIInstall = NULL;
  1814. TCHAR buffer[5];
  1815. LPTSTR Language = Languages;
  1816. TCHAR lpMessage[BUFFER_SIZE];
  1817. LONG_PTR lppArgs[1];
  1818. HMODULE hWbemUpgradeDll = NULL;
  1819. TCHAR szDllPath[MAX_PATH];
  1820. //
  1821. // Load the WBEM upgrade DLL from system wbem folder
  1822. //
  1823. if (GetSystemDirectory(szDllPath, ARRAYSIZE(szDllPath)) &&
  1824. PathAppend(szDllPath, TEXT("wbem\\wbemupgd.dll")))
  1825. {
  1826. hWbemUpgradeDll = LoadLibrary(szDllPath);
  1827. }
  1828. //
  1829. // Fall back to system default path if previous loading fails
  1830. //
  1831. if (!hWbemUpgradeDll)
  1832. {
  1833. hWbemUpgradeDll = LoadLibrary(TEXT("WBEMUPGD.DLL"));
  1834. if (!hWbemUpgradeDll)
  1835. {
  1836. return FALSE;
  1837. }
  1838. }
  1839. //
  1840. // Hook function pointer
  1841. //
  1842. pfnMUIInstall = (pfnMUI_InstallMFLFiles)GetProcAddress(hWbemUpgradeDll, "MUI_InstallMFLFiles");
  1843. if (pfnMUIInstall == NULL)
  1844. {
  1845. FreeLibrary(hWbemUpgradeDll);
  1846. return FALSE;
  1847. }
  1848. // process each language
  1849. while (*Language)
  1850. {
  1851. _tcscpy(buffer, Language);
  1852. if (!pfnMUIInstall(buffer))
  1853. {
  1854. // log error for this language
  1855. LoadString(ghInstance, IDS_MOFCOMPILE_LANG_L, lpMessage, ARRAYSIZE(lpMessage)-1);
  1856. lppArgs[0] = (LONG_PTR)buffer;
  1857. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1858. lpMessage,
  1859. 0,
  1860. 0,
  1861. lpMessage,
  1862. ARRAYSIZE(lpMessage)-1,
  1863. (va_list *)lppArgs);
  1864. LogMessage(lpMessage);
  1865. }
  1866. while (*Language++) // go to the next language and repeat
  1867. {
  1868. }
  1869. } // of while (*Language)
  1870. FreeLibrary(hWbemUpgradeDll);
  1871. return TRUE;
  1872. }
  1873. ////////////////////////////////////////////////////////////////////////////////////
  1874. //
  1875. // UpdateRegistry
  1876. //
  1877. // Update the Registry to account for languages that have been installed
  1878. //
  1879. ////////////////////////////////////////////////////////////////////////////////////
  1880. BOOL UpdateRegistry(LPTSTR Languages,BOOL *lpbFontLinkRegistryTouched)
  1881. {
  1882. TCHAR szRegPath[MAX_PATH];
  1883. TCHAR szValue[] = TEXT("1");
  1884. LPTSTR Language;
  1885. DWORD dwErr;
  1886. HKEY hkey;
  1887. DWORD dwDisp;
  1888. _tcscpy(szRegPath, TEXT("SYSTEM\\CurrentControlSet\\Control\\Nls\\MUILanguages"));
  1889. dwErr = RegCreateKeyEx( HKEY_LOCAL_MACHINE, // handle of an open key
  1890. szRegPath, // address of subkey name
  1891. 0, // reserved
  1892. TEXT("REG_SZ"), // address of class string
  1893. REG_OPTION_NON_VOLATILE , // special options flag
  1894. KEY_ALL_ACCESS, // desired security access
  1895. NULL,
  1896. &hkey, // address of szRegPath for opened handle
  1897. &dwDisp // address of disposition value szRegPath
  1898. );
  1899. if (dwErr != ERROR_SUCCESS)
  1900. {
  1901. return FALSE;
  1902. }
  1903. Language = Languages;
  1904. lstrcpy(szRegPath, TEXT("0409"));
  1905. dwErr = RegSetValueEx( hkey,
  1906. szRegPath,
  1907. 0,
  1908. REG_SZ,
  1909. (const BYTE *)szValue,
  1910. (lstrlen(szValue) + 1) * sizeof(TCHAR));
  1911. while (*Language)
  1912. {
  1913. TCHAR szFontLinkVal[FONTLINK_BUF_SIZE];
  1914. DWORD dwNum;
  1915. lstrcpy(szRegPath, Language);
  1916. dwErr = RegSetValueEx( hkey,
  1917. szRegPath,
  1918. 0,
  1919. REG_SZ,
  1920. (const BYTE *)szValue,
  1921. (lstrlen(szValue) + 1)*sizeof(TCHAR));
  1922. if (dwErr != ERROR_SUCCESS)
  1923. {
  1924. RegCloseKey(hkey);
  1925. return FALSE;
  1926. }
  1927. dwNum = GetPrivateProfileString(TEXT("FontLink"),
  1928. szRegPath,
  1929. TEXT(""),
  1930. szFontLinkVal,
  1931. (sizeof(szFontLinkVal)/sizeof(TCHAR)),
  1932. g_szMUIInfoFilePath);
  1933. if (dwNum)
  1934. {
  1935. SetFontLinkValue(szFontLinkVal,lpbFontLinkRegistryTouched);
  1936. }
  1937. while (*Language++); // go to the next language and repeat
  1938. } // of while (*Language)
  1939. RegCloseKey(hkey);
  1940. return TRUE;
  1941. }
  1942. ////////////////////////////////////////////////////////////////////////////////////
  1943. //
  1944. // UpdateFontLinkRegistry
  1945. //
  1946. // Update the Font Link Registry to account for languages that have been installed
  1947. //
  1948. ////////////////////////////////////////////////////////////////////////////////////
  1949. BOOL UpdateRegistry_FontLink(LPTSTR Languages,BOOL *lpbFontLinkRegistryTouched)
  1950. {
  1951. TCHAR buffer[400];
  1952. LPTSTR Language;
  1953. DWORD dwErr;
  1954. DWORD dwDisp;
  1955. Language = Languages;
  1956. while (*Language)
  1957. {
  1958. TCHAR szFontLinkVal[FONTLINK_BUF_SIZE];
  1959. DWORD dwNum;
  1960. _tcscpy(buffer, Language);
  1961. dwNum = GetPrivateProfileString(TEXT("FontLink"),
  1962. buffer,
  1963. TEXT(""),
  1964. szFontLinkVal,
  1965. (sizeof(szFontLinkVal)/sizeof(TCHAR)),
  1966. g_szMUIInfoFilePath);
  1967. if (dwNum)
  1968. {
  1969. SetFontLinkValue(szFontLinkVal,lpbFontLinkRegistryTouched);
  1970. }
  1971. while (*Language++) // go to the next language and repeat
  1972. {
  1973. }
  1974. } // of while (*Language)
  1975. return TRUE;
  1976. }
  1977. void debug(char *printout)
  1978. {
  1979. #ifdef _DEBUG
  1980. fprintf(stderr, "%s", printout);
  1981. #endif
  1982. }
  1983. ////////////////////////////////////////////////////////////////////////////////////
  1984. //
  1985. // MakeDir
  1986. //
  1987. // Create the directory if it does not already exist
  1988. //
  1989. ////////////////////////////////////////////////////////////////////////////////////
  1990. BOOL MakeDir(LPTSTR szTarget)
  1991. {
  1992. TCHAR lpMessage[BUFFER_SIZE];
  1993. LONG_PTR lppArgs[1];
  1994. if (!FileExists(szTarget)) // if the directory doesn't exist yet
  1995. {
  1996. if (!CreateDirectory( szTarget, NULL)) // create it
  1997. {
  1998. //
  1999. // "LOG: Error creating directory %1"
  2000. //
  2001. LoadString(ghInstance, IDS_CREATEDIR_L, lpMessage, ARRAYSIZE(lpMessage)-1);
  2002. lppArgs[0]=(LONG_PTR)szTarget;
  2003. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  2004. lpMessage,
  2005. 0,
  2006. 0,
  2007. lpMessage,
  2008. ARRAYSIZE(lpMessage)-1,
  2009. (va_list *)lppArgs);
  2010. LogMessage(lpMessage);
  2011. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  2012. NULL,
  2013. GetLastError(),
  2014. 0,
  2015. lpMessage,
  2016. ARRAYSIZE(lpMessage)-1,
  2017. NULL);
  2018. LogMessage(lpMessage);
  2019. return FALSE;
  2020. }
  2021. }
  2022. return TRUE;
  2023. }
  2024. ////////////////////////////////////////////////////////////////////////////////////
  2025. //
  2026. // MakeDirFailed
  2027. //
  2028. // Write message to log file that MakeDir failed.
  2029. //
  2030. ////////////////////////////////////////////////////////////////////////////////////
  2031. BOOL MakeDirFailed(LPTSTR lpDirectory)
  2032. {
  2033. TCHAR lpMessage[BUFFER_SIZE];
  2034. LONG_PTR lppArgs[1];
  2035. //
  2036. // "LOG: MakeDir has failed: %1"
  2037. //
  2038. lppArgs[0]=(LONG_PTR)lpDirectory;
  2039. LogFormattedMessage(NULL, IDS_MAKEDIR_L, lppArgs);
  2040. return TRUE;
  2041. }
  2042. ////////////////////////////////////////////////////////////////////////////////////
  2043. //
  2044. // CopyFileFailed
  2045. // Write message to log file that CopyFile failed.
  2046. //
  2047. ////////////////////////////////////////////////////////////////////////////////////
  2048. BOOL CopyFileFailed(LPTSTR lpFile,DWORD dwErrorCode)
  2049. {
  2050. TCHAR lpMessage[BUFFER_SIZE];
  2051. LONG_PTR lppArgs[1];
  2052. DWORD MessageID;
  2053. if ( dwErrorCode)
  2054. {
  2055. MessageID = dwErrorCode;
  2056. }
  2057. else
  2058. {
  2059. MessageID = GetLastError();
  2060. }
  2061. //
  2062. // "LOG: CopyFile has failed: %1"
  2063. //
  2064. LoadString(ghInstance, IDS_COPYFILE_L, lpMessage, ARRAYSIZE(lpMessage)-1);
  2065. lppArgs[0]=(LONG_PTR)lpFile;
  2066. FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  2067. lpMessage,
  2068. 0,
  2069. 0,
  2070. lpMessage,
  2071. ARRAYSIZE(lpMessage)-1,
  2072. (va_list *)lppArgs);
  2073. LogMessage(lpMessage);
  2074. FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM,
  2075. NULL,
  2076. MessageID,
  2077. 0,
  2078. lpMessage,
  2079. ARRAYSIZE(lpMessage)-1,
  2080. NULL);
  2081. LogMessage(lpMessage);
  2082. return TRUE;
  2083. }
  2084. ////////////////////////////////////////////////////////////////////////////
  2085. //
  2086. // Muisetup_InitInf
  2087. //
  2088. // Parameters:
  2089. //
  2090. // [OUT] phInf the handle to the INF file opened.
  2091. // [OUT] pFileQueue the file queue created in this function.
  2092. // [OUT] pQueueContext the context used by the default queue callback routine included with the Setup API.
  2093. //
  2094. ////////////////////////////////////////////////////////////////////////////
  2095. BOOL Muisetup_InitInf(
  2096. HWND hDlg,
  2097. LPTSTR pszInf,
  2098. HINF *phInf,
  2099. HSPFILEQ *pFileQueue,
  2100. PVOID *pQueueContext)
  2101. {
  2102. //
  2103. // Open the Inf file.
  2104. //
  2105. *phInf = SetupOpenInfFile(pszInf, NULL, INF_STYLE_WIN4, NULL);
  2106. if (*phInf == INVALID_HANDLE_VALUE)
  2107. {
  2108. return FALSE;
  2109. }
  2110. //
  2111. // Create a setup file queue and initialize default setup
  2112. // copy queue callback context.
  2113. //
  2114. *pFileQueue = SetupOpenFileQueue();
  2115. if ((!*pFileQueue) || (*pFileQueue == INVALID_HANDLE_VALUE))
  2116. {
  2117. SetupCloseInfFile(*phInf);
  2118. return FALSE;
  2119. }
  2120. *pQueueContext = SetupInitDefaultQueueCallback(hDlg);
  2121. if (!*pQueueContext)
  2122. {
  2123. SetupCloseFileQueue(*pFileQueue);
  2124. SetupCloseInfFile(*phInf);
  2125. return FALSE;
  2126. }
  2127. //
  2128. // Return success.
  2129. //
  2130. return TRUE;
  2131. }
  2132. ////////////////////////////////////////////////////////////////////////////
  2133. //
  2134. // Muisetup_CloseInf
  2135. //
  2136. ////////////////////////////////////////////////////////////////////////////
  2137. BOOL Muisetup_CloseInf(
  2138. HINF hInf,
  2139. HSPFILEQ FileQueue,
  2140. PVOID QueueContext)
  2141. {
  2142. //
  2143. // Terminate the Queue.
  2144. //
  2145. SetupTermDefaultQueueCallback(QueueContext);
  2146. //
  2147. // Close the file queue.
  2148. //
  2149. SetupCloseFileQueue(FileQueue);
  2150. //
  2151. // Close the Inf file.
  2152. //
  2153. SetupCloseInfFile(hInf);
  2154. return TRUE;
  2155. }
  2156. UINT MySetupQueueCallback (
  2157. PVOID QueueContext,
  2158. UINT Notification,
  2159. UINT_PTR Param1,
  2160. UINT_PTR Param2
  2161. )
  2162. {
  2163. UINT status;
  2164. PFILEPATHS FilePaths = (PFILEPATHS)Param1;
  2165. PSOURCE_MEDIA SourceMedia = (PSOURCE_MEDIA)Param1;
  2166. TCHAR szFileName[MAX_PATH];
  2167. int iLen;
  2168. if(Notification == SPFILENOTIFY_NEEDMEDIA)
  2169. {
  2170. if(SourceMedia->SourcePath && SourceMedia->SourceFile)
  2171. {
  2172. _tcscpy(szFileName,SourceMedia->SourcePath);
  2173. _tcscat(szFileName,TEXT("\\"));
  2174. _tcscat(szFileName,SourceMedia->SourceFile);
  2175. if (!FileExists(szFileName))
  2176. {
  2177. CopyFileFailed(szFileName,ERROR_FILE_NOT_FOUND);
  2178. g_IECopyError=TRUE;
  2179. return FILEOP_SKIP;
  2180. }
  2181. }
  2182. }
  2183. if (Notification == SPFILENOTIFY_COPYERROR)
  2184. {
  2185. CopyFileFailed((LPTSTR)FilePaths->Source,ERROR_FILE_NOT_FOUND);
  2186. g_IECopyError=TRUE;
  2187. return FILEOP_SKIP;
  2188. }
  2189. //
  2190. // Special for .htt file
  2191. //
  2192. // Sign webvw htt files in order for the shell to grant them security privilege to execute stuff.
  2193. //
  2194. if ( (Notification == SPFILENOTIFY_ENDCOPY) && (FilePaths->Win32Error == ERROR_SUCCESS))
  2195. {
  2196. iLen=_tcslen(FilePaths->Target);
  2197. if (iLen > 4)
  2198. {
  2199. if (_tcsicmp(&FilePaths->Target[iLen - 4], TEXT(".htt")) == 0)
  2200. {
  2201. SHRegisterValidateTemplate(FilePaths->Target,SHRVT_REGISTER);
  2202. }
  2203. }
  2204. }
  2205. status= SetupDefaultQueueCallback(QueueContext,Notification, Param1, Param2);
  2206. if (status == FILEOP_ABORT)
  2207. {
  2208. g_InstallCancelled = TRUE;
  2209. }
  2210. return status;
  2211. }
  2212. ////////////////////////////////////////////////////////////////////////////////////
  2213. //
  2214. // ExecuteComponentINF
  2215. //
  2216. // Installs component MUI files, by running the specified INF file.
  2217. //
  2218. // Parameters:
  2219. // pComponentName the name of the component (e.g. "ie5")
  2220. // pComponentInfFile: the full path of the component INF file.
  2221. // pInstallSection the section in the component INF file to be executed. (e.g "DefaultInstall" or "Uninstall")
  2222. //
  2223. ////////////////////////////////////////////////////////////////////////////////////
  2224. BOOL ExecuteComponentINF(
  2225. HWND hDlg, PTSTR pComponentName, PTSTR pComponentInfFile, PTSTR pInstallSection, BOOL bInstall)
  2226. {
  2227. int iLen;
  2228. TCHAR tchCommandParam[BUFFER_SIZE];
  2229. CHAR chCommandParam[BUFFER_SIZE*sizeof(TCHAR)];
  2230. HINF hCompInf; // the handle to the component INF file.
  2231. HSPFILEQ FileQueue;
  2232. PVOID QueueContext;
  2233. BOOL bRet = TRUE;
  2234. DWORD dwResult;
  2235. LONG_PTR lppArgs[3];
  2236. TCHAR szBuffer[BUFFER_SIZE];
  2237. //
  2238. // Advpack LaunchINFSection() command line format:
  2239. // INF file, INF section, flags, reboot string
  2240. // 'N' or 'n' in reboot string means no reboot message popup.
  2241. //
  2242. wsprintf(tchCommandParam, TEXT("%s,%s,0,n"), pComponentInfFile, pInstallSection);
  2243. WideCharToMultiByte(CP_ACP, 0, tchCommandParam, -1, chCommandParam, sizeof(chCommandParam), NULL, NULL);
  2244. if (FileExists(pComponentInfFile))
  2245. {
  2246. // gpfnLaunchINFSection won't be NULL since InitializePFNs() already verifies that.
  2247. if ((gpfnLaunchINFSection)(hDlg, ghInstance, chCommandParam, SW_SHOW) != S_OK)
  2248. {
  2249. lppArgs[0] = (LONG_PTR)pComponentName;
  2250. DoMessageBoxFromResource(hDlg, ghInstance, bInstall? IDS_ERROR_INSTALL_COMP_UI : IDS_ERROR_UNINSTALL_COMP_UI, lppArgs, IDS_ERROR_T, MB_OK);
  2251. return (FALSE);
  2252. }
  2253. }
  2254. return (TRUE);
  2255. }
  2256. ////////////////////////////////////////////////////////////////////////////////////
  2257. //
  2258. // CheckProductType
  2259. //
  2260. // Check product type of W2K
  2261. //
  2262. ////////////////////////////////////////////////////////////////////////////////////
  2263. BOOL CheckProductType(INT_PTR nType)
  2264. {
  2265. OSVERSIONINFOEX verinfo;
  2266. INT64 dwConditionMask=0;
  2267. BOOL bResult=FALSE;
  2268. DWORD dwTypeMask = VER_PRODUCT_TYPE;
  2269. memset(&verinfo,0,sizeof(verinfo));
  2270. verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  2271. VER_SET_CONDITION(dwConditionMask,VER_PRODUCT_TYPE,VER_EQUAL);
  2272. switch (nType)
  2273. {
  2274. // W2K Professional
  2275. case MUI_IS_WIN2K_PRO:
  2276. verinfo.wProductType=VER_NT_WORKSTATION;
  2277. break;
  2278. // W2K Server
  2279. case MUI_IS_WIN2K_SERVER:
  2280. verinfo.wProductType=VER_NT_SERVER;
  2281. break;
  2282. // W2K Advanced Server or Data Center
  2283. case MUI_IS_WIN2K_ADV_SERVER_OR_DATACENTER:
  2284. verinfo.wProductType=VER_NT_SERVER;
  2285. verinfo.wSuiteMask =VER_SUITE_ENTERPRISE;
  2286. VER_SET_CONDITION(dwConditionMask,VER_SUITENAME,VER_OR);
  2287. dwTypeMask = VER_PRODUCT_TYPE | VER_SUITENAME;
  2288. break;
  2289. // W2k Data Center
  2290. case MUI_IS_WIN2K_DATACENTER:
  2291. verinfo.wProductType=VER_NT_SERVER;
  2292. verinfo.wSuiteMask =VER_SUITE_DATACENTER;
  2293. VER_SET_CONDITION(dwConditionMask,VER_SUITENAME,VER_OR);
  2294. dwTypeMask = VER_PRODUCT_TYPE | VER_SUITENAME;
  2295. break;
  2296. // W2K Domain Controller
  2297. case MUI_IS_WIN2K_DC:
  2298. verinfo.wProductType=VER_NT_DOMAIN_CONTROLLER;
  2299. break;
  2300. case MUI_IS_WIN2K_ENTERPRISE:
  2301. verinfo.wProductType=VER_NT_DOMAIN_CONTROLLER;
  2302. verinfo.wSuiteMask =VER_SUITE_ENTERPRISE;
  2303. VER_SET_CONDITION(dwConditionMask,VER_SUITENAME,VER_OR);
  2304. dwTypeMask = VER_PRODUCT_TYPE | VER_SUITENAME;
  2305. break;
  2306. case MUI_IS_WIN2K_DC_DATACENTER:
  2307. verinfo.wProductType=VER_NT_DOMAIN_CONTROLLER;
  2308. verinfo.wSuiteMask =VER_SUITE_DATACENTER;
  2309. VER_SET_CONDITION(dwConditionMask,VER_SUITENAME,VER_OR);
  2310. dwTypeMask = VER_PRODUCT_TYPE | VER_SUITENAME;
  2311. break;
  2312. // Whistler Personal
  2313. case MUI_IS_WIN2K_PERSONAL:
  2314. verinfo.wProductType=VER_NT_WORKSTATION;
  2315. verinfo.wSuiteMask =VER_SUITE_PERSONAL;
  2316. VER_SET_CONDITION(dwConditionMask,VER_SUITENAME,VER_AND);
  2317. dwTypeMask = VER_PRODUCT_TYPE | VER_SUITENAME;
  2318. break;
  2319. default:
  2320. verinfo.wProductType=VER_NT_WORKSTATION;
  2321. break;
  2322. }
  2323. return (VerifyVersionInfo(&verinfo,dwTypeMask,dwConditionMask));
  2324. }