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.

1922 lines
63 KiB

  1. // adminpak.cpp : Defines the entry point for the DLL application.
  2. //
  3. #include "stdafx.h"
  4. #include <stdio.h>
  5. #include <shellapi.h>
  6. #include "shlobj.h"
  7. #include "adminpak.h"
  8. #define STRSAFE_NO_DEPRECATE
  9. #include "strsafe.h"
  10. #include "shlwapi.h"
  11. // version resource specific structures
  12. typedef struct __tagLanguageAndCodePage {
  13. WORD wLanguage;
  14. WORD wCodePage;
  15. } TTRANSLATE, *PTTRANSLATE;
  16. typedef struct __tagVersionBreakup {
  17. DWORD dwMajor;
  18. DWORD dwMinor;
  19. DWORD dwRevision; // build number
  20. DWORD dwSubRevision; // QFE / SP
  21. } TVERSION, *PTVERSION;
  22. enum {
  23. translateError = -2,
  24. translateLesser = -1, translateEqual = 0, translateGreater = 1,
  25. translateWrongFile = 2
  26. };
  27. #define ADMINPAK_EXPORTS 1
  28. BOOL APIENTRY DllMain( HANDLE hModule,
  29. DWORD ul_reason_for_call,
  30. LPVOID lpReserved
  31. )
  32. {
  33. UNREFERENCED_PARAMETER( hModule );
  34. UNREFERENCED_PARAMETER( lpReserved );
  35. switch (ul_reason_for_call)
  36. {
  37. case DLL_PROCESS_ATTACH:
  38. case DLL_THREAD_ATTACH:
  39. case DLL_THREAD_DETACH:
  40. case DLL_PROCESS_DETACH:
  41. break;
  42. }
  43. return TRUE;
  44. }
  45. ///////////////////////////////////////////////////////////////////////////////////////////////
  46. ///////////////////////////////////////////////////////////////////////////////////////////////
  47. ///////////////////////////////////////////////////////////////////////////////////////////////
  48. ///////////////////////////////////////////////////////////////////////////////////////////////
  49. ///////////////////////////////////////////////////////////////////////////////////////////////
  50. ///////////////////////////////////////////////////////////////////////////////////////////////
  51. ///////////////////////////////////////////////////////////////////////////////////////////////
  52. ///////////////////////////////////////////////////////////////////////////////////////////////
  53. ///////////////////////////////////////////////////////////////////////////////////////////////
  54. ///////////////////////////////////////////////////////////////////////////////////////////////
  55. ///////////////////////////////////////////////////////////////////////////////////////////////
  56. ///////////////////////////////////////////////////////////////////////////////////////////////
  57. // CMAK Migration Code
  58. //
  59. // Define Strings Chars
  60. //
  61. static const CHAR c_szDaoClientsPath[] = "SOFTWARE\\Microsoft\\Shared Tools\\DAO\\Clients";
  62. static const CHAR c_szCmakRegPath[] = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\CMAK.EXE";
  63. static const CHAR c_szPathValue[] = "Path";
  64. static const CHAR c_szProfiles32Fmt[] = "%s\\Profiles-32";
  65. static const CHAR c_szCm32Fmt[] = "%s\\cm32";
  66. static const CHAR c_szProfilesFmt[] = "%s\\Profiles";
  67. static const CHAR c_szSupportFmt[] = "%s\\Support";
  68. static const CHAR c_szCmHelpFmt[] = "%s\\Support\\CmHelp";
  69. static const CHAR c_szCmakGroup[] = "Connection Manager Administration Kit";
  70. static const CHAR OC_OLD_IEAK_DOCDIR[] = "Docs";
  71. static const CHAR OC_NTOP4_GROUPNAME[] = "Windows NT 4.0 Option Pack";
  72. static const CHAR OC_ICS_GROUPNAME[] = "Internet Connection Services for RAS";
  73. static const CHAR OC_ADMIN_TOOLS[] = "\\Administrative Tools\\Phone Book Administrator.lnk";
  74. static const CHAR OC_PBA_DESC[] = "Use Phone Book Administrator to create Connection Manager Phone Book ";
  75. static const CHAR OC_PWS_GROUPNAME[] = "Microsoft Personal Web Server";
  76. const DWORD c_dwCmakDirID = 123174; // just must be larger than DIRID_USER = 0x8000;
  77. //
  78. // Define Functions
  79. //
  80. BOOL migrateProfiles(LPCTSTR pszSource, LPCTSTR pszDestination, LPCTSTR pszDestinationProfiles);
  81. void DeleteOldCmakSubDirs(LPCTSTR pszCmakPath);
  82. void DeleteProgramGroupWithLinks(LPCTSTR pszGroupPath);
  83. void DeleteOldNtopLinks();
  84. void DeleteIeakCmakLinks();
  85. void DeleteCmakRegKeys();
  86. void CreateNewProfilesDirectory( LPCTSTR pszNewProfilePath );
  87. HRESULT HrGetPBAPathIfInstalled(PSTR pszCpaPath, DWORD dwNumChars);
  88. BOOL GetAdminToolsFolder(PSTR pszAdminTools);
  89. HRESULT HrCreatePbaShortcut(PSTR pszCpaPath);
  90. // This function migrates the old profile versions of CMAK to the new one placed
  91. // by the adminpak....
  92. extern "C" ADMINPAK_API int __stdcall fnMigrateProfilesToNewCmak( MSIHANDLE hInstall )
  93. {
  94. OutputDebugString("ADMINPAK: fnMigrateProfilesToNewCmak...\n");
  95. // Get the location of the old CMAK folder.
  96. DWORD dwPathLength = MAX_PATH * sizeof(char);
  97. char *szCmakOldPath = NULL;
  98. DWORD dwCmakOldPathLen = dwPathLength;
  99. char *szCmakOldProfilePath = NULL;
  100. DWORD dwCmakOldProfilePathLen = dwPathLength;
  101. char *szCmakNewPath = NULL;
  102. DWORD dwCmakNewPathLen = dwPathLength;
  103. char *szCmakNewProfilePath = NULL;
  104. DWORD dwCmakNewProfilePathLen = dwPathLength;
  105. long sc;
  106. UINT uintRet;
  107. HKEY phkResult = NULL;
  108. HRESULT res = S_OK;
  109. #if (defined(DBG) || defined(_DEBUG) || defined(DEBUG))
  110. char tempOut1[MAX_PATH];
  111. #endif
  112. szCmakOldPath = new char[dwCmakOldPathLen];
  113. szCmakNewPath = new char[dwCmakNewPathLen];
  114. szCmakOldProfilePath = new char[dwCmakOldProfilePathLen];
  115. szCmakNewProfilePath = new char[dwCmakNewProfilePathLen];
  116. if ( szCmakOldPath == NULL ||
  117. szCmakNewPath == NULL ||
  118. szCmakOldProfilePath == NULL ||
  119. szCmakNewProfilePath == NULL )
  120. {
  121. if ( szCmakOldPath != NULL )
  122. {
  123. delete [] szCmakOldPath;
  124. }
  125. if ( szCmakNewPath != NULL )
  126. {
  127. delete [] szCmakNewPath;
  128. }
  129. if ( szCmakOldProfilePath != NULL )
  130. {
  131. delete [] szCmakOldProfilePath;
  132. }
  133. if ( szCmakNewProfilePath != NULL )
  134. {
  135. delete [] szCmakNewProfilePath;
  136. }
  137. return E_OUTOFMEMORY;
  138. }
  139. // Put together OLD path information
  140. sc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, c_szCmakRegPath, 0, KEY_READ, &phkResult);
  141. if ( sc != ERROR_SUCCESS )
  142. {
  143. delete [] szCmakOldPath;
  144. delete [] szCmakOldProfilePath;
  145. delete [] szCmakNewPath;
  146. delete [] szCmakNewProfilePath;
  147. return sc;
  148. }
  149. sc = RegQueryValueEx( phkResult, "Path", NULL, NULL, (unsigned char*)szCmakOldPath, &dwCmakOldPathLen );
  150. RegCloseKey( phkResult );
  151. // sc = ERROR_SUCCESS;
  152. // strcpy(szCmakOldPath, "c:\\cmak\\");
  153. if ( sc == ERROR_SUCCESS ) {
  154. dwCmakOldPathLen = (DWORD)strlen( szCmakOldPath );
  155. char tmpLastChar = *(szCmakOldPath + (dwCmakOldPathLen - 1));
  156. if ( tmpLastChar == '\\' ) {
  157. *(szCmakOldPath + (dwCmakOldPathLen - 1)) = NULL;
  158. dwCmakOldPathLen = (DWORD)strlen( szCmakOldPath );
  159. }
  160. #if (defined(DBG) || defined(_DEBUG) || defined(DEBUG))
  161. // StringCchPrintf(tempOut1, "ADMINPAK: szCmakOldPath: %s\n", szCmakOldPath);
  162. OutputDebugString( tempOut1 );
  163. #endif
  164. res = StringCchCopy( szCmakOldProfilePath, dwPathLength, szCmakOldPath );
  165. dwCmakOldProfilePathLen = dwCmakOldPathLen;
  166. res = StringCchCat(szCmakOldProfilePath, dwPathLength, "\\Profiles");
  167. dwCmakOldProfilePathLen = (DWORD)strlen( szCmakOldProfilePath );
  168. }
  169. // Put together NEW path information
  170. uintRet = MsiGetTargetPath( hInstall, "DirCMAK", szCmakNewPath, &dwCmakNewPathLen);
  171. // uintRet = ERROR_SUCCESS;
  172. // strcpy(szCmakNewPath, "c:\\cmak\\program files");
  173. if ( uintRet == ERROR_SUCCESS ) {
  174. dwCmakNewPathLen = (DWORD)strlen( szCmakNewPath );
  175. char tmpLastChar = *(szCmakNewPath + (dwCmakNewPathLen - 1));
  176. if ( tmpLastChar == '\\' ) {
  177. *(szCmakNewPath + (dwCmakNewPathLen - 1)) = NULL;
  178. dwCmakNewPathLen = (DWORD)strlen( szCmakNewPath );
  179. }
  180. #if (defined(DBG) || defined(_DEBUG) || defined(DEBUG))
  181. // StringCchPrintf(tempOut1, "ADMINPAK: szCmakNewPath: %s\n", szCmakNewPath);
  182. OutputDebugString( tempOut1 );
  183. #endif
  184. res = StringCchCopy( szCmakNewProfilePath, dwPathLength, szCmakNewPath );
  185. dwCmakNewProfilePathLen = dwCmakNewPathLen;
  186. res = StringCchCat(szCmakNewProfilePath, dwPathLength, "\\Profiles");
  187. dwCmakNewProfilePathLen = strlen( szCmakNewProfilePath );
  188. }
  189. // if all is Success then DO IT!
  190. if ( sc == ERROR_SUCCESS && uintRet == ERROR_SUCCESS && res == S_OK) {
  191. // RenameProfiles32(LPCTSTR pszCMAKpath, LPCTSTR pszProfilesDir);
  192. // RenameProfiles32( szCmakOldPath, szCmakNewProfilePath );
  193. // BOOL migrateProfiles(PCWSTR pszSource, LPCTSTR pszDestination);
  194. migrateProfiles( szCmakOldPath, szCmakNewPath, szCmakNewProfilePath );
  195. // DeleteOldCmakSubDirs(LPCTSTR pszCmakPath);
  196. DeleteOldCmakSubDirs( szCmakOldPath );
  197. }
  198. delete [] szCmakOldPath;
  199. delete [] szCmakOldProfilePath;
  200. delete [] szCmakNewPath;
  201. delete [] szCmakNewProfilePath;
  202. return ERROR_SUCCESS;
  203. }
  204. extern "C" ADMINPAK_API int __stdcall fnDeleteOldCmakVersion( MSIHANDLE hInstall )
  205. {
  206. OutputDebugString("ADMINPAK: fnDeleteOldCmakVersion...\n");
  207. // If PBA exists, you need to
  208. CHAR szPbaInstallPath[MAX_PATH+1];
  209. HRESULT hr;
  210. hr = HrGetPBAPathIfInstalled(szPbaInstallPath, MAX_PATH);
  211. UNREFERENCED_PARAMETER( hInstall );
  212. if (S_OK == hr)
  213. {
  214. HrCreatePbaShortcut(szPbaInstallPath);
  215. }
  216. DeleteOldNtopLinks();
  217. DeleteIeakCmakLinks();
  218. DeleteCmakRegKeys();
  219. return ERROR_SUCCESS;
  220. }
  221. ///////////////////////////////////////////////////////////////////////////////////////////////
  222. ///////////////////////////////////////////////////////////////////////////////////////////////
  223. //+---------------------------------------------------------------------------
  224. //
  225. // Function: migrateProfiles
  226. //
  227. // Purpose: This is the function that migrates the profiles. It takes the current
  228. // CMAK dir as its first input and the new CMAK dir as its second input..
  229. //
  230. // Arguments: PCWSTR pszSource - root of source CMAK dir
  231. // PCWSTR pszDestination - root of destination CMAK dir
  232. //
  233. // Returns: BOOL - Returns TRUE if it was able to migrate the profiles.
  234. //
  235. // Author: a-anasj 9 Mar 1998
  236. //
  237. // Notes:
  238. // History: quintinb Created 12/9/97
  239. //
  240. BOOL migrateProfiles(LPCTSTR pszSource, LPCTSTR pszDestination, LPCTSTR pszDestinationProfiles)
  241. {
  242. OutputDebugString("ADMINPAK: migrateProfiles...\n");
  243. CHAR szSourceProfileSearchString1[MAX_PATH+1] ="" ;
  244. CHAR szSourceProfileSearchString2[MAX_PATH+1] = "";
  245. CHAR szFile[MAX_PATH+1] = "";
  246. HANDLE hFileSearch;
  247. WIN32_FIND_DATA fdFindData;
  248. BOOL bReturn = TRUE;
  249. SHFILEOPSTRUCT fOpStruct;
  250. DWORD dwSize = _MAX_PATH;
  251. HRESULT res;
  252. //
  253. // Initialize the searchstring and the destination dir
  254. //
  255. //StringCchPrintf(szSourceProfileSearchString1, "%s\\*.*", pszSource);
  256. //
  257. // Create the destination directory
  258. //
  259. CreateNewProfilesDirectory( pszDestinationProfiles );
  260. // ::CreateDirectory(pszDestination, NULL); //lint !e534 this might fail if it already exists
  261. hFileSearch = FindFirstFile(szSourceProfileSearchString1, &fdFindData);
  262. while (INVALID_HANDLE_VALUE != hFileSearch)
  263. {
  264. if((fdFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  265. (0 != _stricmp(fdFindData.cFileName, "cm32")) && // 1.1/1.2 Legacy
  266. (0 != _stricmp(fdFindData.cFileName, "cm16")) && // 1.1/1.2 Legacy
  267. (0 != _stricmp(fdFindData.cFileName, "Docs")) &&
  268. (0 != _stricmp(fdFindData.cFileName, "Profiles-32")) && // 1.1/1.2 Legacy
  269. (0 != _stricmp(fdFindData.cFileName, "Profiles-16")) && // 1.1/1.2 Legacy
  270. (0 != _stricmp(fdFindData.cFileName, "Support")) &&
  271. (0 != _stricmp(fdFindData.cFileName, "Profiles")) &&
  272. (0 != _stricmp(fdFindData.cFileName, ".")) &&
  273. (0 != _stricmp(fdFindData.cFileName, "..")))
  274. {
  275. //
  276. // Then I have a profile directory
  277. //
  278. ZeroMemory(&fOpStruct, sizeof(fOpStruct));
  279. ZeroMemory(szFile, sizeof(szFile));
  280. //StringCchPrintf(szFile, "%s\\%s", pszSource, fdFindData.cFileName);
  281. fOpStruct.hwnd = NULL;
  282. fOpStruct.wFunc = FO_MOVE;
  283. fOpStruct.pTo = pszDestinationProfiles;
  284. fOpStruct.pFrom = szFile;
  285. fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_RENAMEONCOLLISION;
  286. bReturn &= (0== SHFileOperation(&fOpStruct)); //lint !e514, intended use of boolean, quintinb
  287. }
  288. else if((fdFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  289. ((0 == _stricmp(fdFindData.cFileName, "Profiles")) ||// 1.1/1.2 Legacy
  290. (0 == _stricmp(fdFindData.cFileName, "Profiles-32")) ||// 1.1/1.2 Legacy
  291. (0 == _stricmp(fdFindData.cFileName, "Profiles-16"))) )// 1.1/1.2 Legacy
  292. {
  293. //
  294. // Then I have a profile directory
  295. //
  296. res = StringCchCopy(szSourceProfileSearchString2, dwSize, pszSource);
  297. res = StringCchCat(szSourceProfileSearchString2, dwSize,"\\");
  298. res = StringCchCat(szSourceProfileSearchString2, dwSize,fdFindData.cFileName);
  299. //StringCchPrintf(szSourceProfileSearchString2, "%s\\*.*", szSourceProfileSearchString2);
  300. if (res == S_OK)
  301. {
  302. HANDLE hFileSearch2;
  303. WIN32_FIND_DATA fdFindData2;
  304. hFileSearch2 = FindFirstFile(szSourceProfileSearchString2, &fdFindData2);
  305. while (INVALID_HANDLE_VALUE != hFileSearch2)
  306. {
  307. if((fdFindData2.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  308. (0 != _stricmp(fdFindData2.cFileName, ".")) &&
  309. (0 != _stricmp(fdFindData2.cFileName, "..")))
  310. {
  311. ZeroMemory(&fOpStruct, sizeof(fOpStruct));
  312. ZeroMemory(szFile, sizeof(szFile));
  313. //StringCchPrintf(szFile, "%s\\%s\\%s", pszSource, fdFindData.cFileName, fdFindData2.cFileName);
  314. fOpStruct.hwnd = NULL;
  315. fOpStruct.wFunc = FO_MOVE;
  316. fOpStruct.pTo = pszDestinationProfiles;
  317. fOpStruct.pTo = NULL;
  318. fOpStruct.pFrom = szFile;
  319. fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_RENAMEONCOLLISION;
  320. bReturn &= (0== SHFileOperation(&fOpStruct)); //lint !e514, intended use of boolean, quintinb
  321. }
  322. if (!FindNextFile(hFileSearch2, &fdFindData2)) {
  323. // Delete the folder
  324. if ( 0 != _stricmp(fdFindData.cFileName, "Profiles") ) {
  325. //StringCchPrintf(szFile, "%s\\%s", pszSource, fdFindData.cFileName);
  326. ::RemoveDirectory(szFile);
  327. }
  328. break;
  329. }
  330. }
  331. if (INVALID_HANDLE_VALUE != hFileSearch2) {
  332. FindClose(hFileSearch2);
  333. }
  334. }
  335. }
  336. //Modified by v-mmosko. Need speical case to leave behind these 2 files
  337. else if ( 0 != _stricmp(fdFindData.cFileName, "cmproxy.dll") ||
  338. 0 != _stricmp(fdFindData.cFileName, "cmroute.dll") )
  339. {
  340. }
  341. else if ( 0 != _stricmp(fdFindData.cFileName, ".") &&
  342. 0 != _stricmp(fdFindData.cFileName, "..") )
  343. {
  344. ZeroMemory(&fOpStruct, sizeof(fOpStruct));
  345. ZeroMemory(szFile, sizeof(szFile));
  346. //StringCchPrintf(szFile, "%s\\%s", pszSource, fdFindData.cFileName);
  347. fOpStruct.hwnd = NULL;
  348. fOpStruct.wFunc = FO_DELETE;
  349. fOpStruct.pFrom = szFile;
  350. fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
  351. bReturn &= (0== SHFileOperation(&fOpStruct)); //lint !e514, intended use of boolean, quintinb
  352. }
  353. //
  354. // Check to see if we have any more Files
  355. //
  356. if (!FindNextFile(hFileSearch, &fdFindData))
  357. {
  358. if (ERROR_NO_MORE_FILES != GetLastError())
  359. {
  360. //
  361. // We had some unexpected error, report unsuccessful completion
  362. //
  363. bReturn = FALSE;
  364. }
  365. // Exit loop
  366. break;
  367. }
  368. }
  369. if (INVALID_HANDLE_VALUE != hFileSearch)
  370. {
  371. FindClose(hFileSearch);
  372. }
  373. //
  374. // Delete the old CMAK directory if it is not the same as the new directory.
  375. //
  376. if ( 0 != _stricmp(pszSource, pszDestination) ) {
  377. ZeroMemory(&fOpStruct, sizeof(fOpStruct));
  378. fOpStruct.hwnd = NULL;
  379. fOpStruct.wFunc = FO_DELETE;
  380. fOpStruct.pTo = NULL;
  381. fOpStruct.pFrom = pszSource;
  382. fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
  383. bReturn &= (0== SHFileOperation(&fOpStruct)); //lint !e514, intended use of boolean, quintinb
  384. }
  385. return bReturn;
  386. }
  387. //+---------------------------------------------------------------------------
  388. //
  389. // Function: DeleteOldCmakSubDirs
  390. //
  391. // Purpose: Deletes the old Cmak sub directories. Uses FindFirstFile becuase
  392. // we don't want to delete any customized doc files that the user may
  393. // have customized. Thus anything in the CMHelp directory except the
  394. // original help files is deleted.
  395. //
  396. // Arguments: PCWSTR pszCMAKpath - current cmak path
  397. //
  398. // Returns: Nothing
  399. //
  400. // Author: quintinb 6 Nov 1998
  401. //
  402. // Notes:
  403. void DeleteOldCmakSubDirs(LPCTSTR pszCmakPath)
  404. {
  405. UNREFERENCED_PARAMETER( pszCmakPath );
  406. OutputDebugString("ADMINPAK: DeleteOldCmakSubDirs...\n");
  407. CHAR szCm32path[MAX_PATH+1];
  408. CHAR szCm32SearchString[MAX_PATH+1];
  409. CHAR szTemp[MAX_PATH+1];
  410. HANDLE hCm32FileSearch;
  411. WIN32_FIND_DATA fdCm32;
  412. //
  413. // Delete the old IEAK Docs Dir
  414. //
  415. //StringCchPrintf(szTemp, "%s\\%s", pszCmakPath, OC_OLD_IEAK_DOCDIR);
  416. RemoveDirectory(szTemp);
  417. //StringCchPrintf(szCm32path, c_szCm32Fmt, pszCmakPath);
  418. //
  419. // First look in the Cm32 directory itself. Delete all files found, continue down
  420. // into subdirs.
  421. //
  422. //StringCchPrintf(szCm32SearchString, "%s\\*.*", szCm32path);
  423. hCm32FileSearch = FindFirstFile(szCm32SearchString, &fdCm32);
  424. while (INVALID_HANDLE_VALUE != hCm32FileSearch)
  425. {
  426. if (fdCm32.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  427. {
  428. if ((0 != _stricmp(fdCm32.cFileName, ".")) &&
  429. (0 != _stricmp(fdCm32.cFileName, "..")))
  430. {
  431. //
  432. // Then we want to delete all the files in this lang sub dir and we
  433. // we want to delete the four help files from the CM help dir. If all the
  434. // files are deleted from a dir then we should remove the directory.
  435. //
  436. CHAR szLangDirSearchString[MAX_PATH+1];
  437. HANDLE hLangDirFileSearch;
  438. WIN32_FIND_DATA fdLangDir;
  439. //StringCchPrintf(szLangDirSearchString, "%s\\%s\\*.*", szCm32path, fdCm32.cFileName);
  440. hLangDirFileSearch = FindFirstFile(szLangDirSearchString, &fdLangDir);
  441. while (INVALID_HANDLE_VALUE != hLangDirFileSearch)
  442. {
  443. if (fdLangDir.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  444. {
  445. if ((0 != _stricmp(fdLangDir.cFileName, ".")) &&
  446. (0 != _stricmp(fdLangDir.cFileName, "..")))
  447. {
  448. //
  449. // We only want to delete help files from our help source dirs
  450. //
  451. if (0 == _strnicmp(fdLangDir.cFileName, "CM", 2))
  452. {
  453. //
  454. // Delete the four help files only.
  455. //
  456. //StringCchPrintf(szTemp, "%s\\%s\\%s\\cmctx32.rtf", szCm32path, fdCm32.cFileName, fdLangDir.cFileName);
  457. DeleteFile(szTemp);
  458. //StringCchPrintf(szTemp, "%s\\%s\\%s\\cmmgr32.h", szCm32path, fdCm32.cFileName, fdLangDir.cFileName);
  459. DeleteFile(szTemp);
  460. //StringCchPrintf(szTemp, "%s\\%s\\%s\\cmmgr32.hpj", szCm32path, fdCm32.cFileName, fdLangDir.cFileName);
  461. DeleteFile(szTemp);
  462. //StringCchPrintf(szTemp, "%s\\%s\\%s\\cmtrb32.rtf", szCm32path, fdCm32.cFileName, fdLangDir.cFileName);
  463. DeleteFile(szTemp);
  464. //
  465. // Now try to remove the directory
  466. //
  467. //StringCchPrintf(szTemp, "%s\\%s\\%s", szCm32path, fd32.cFileName, fdLangDir.cFileName);
  468. RemoveDirectory(szTemp);
  469. }
  470. }
  471. }
  472. else
  473. {
  474. //StringCchPrintf(szTemp, "%s\\%s\\%s", szCm32path, fdCm32.cFileName, fdLangDir.cFileName);
  475. DeleteFile(szTemp);
  476. }
  477. //
  478. // Check to see if we have any more Files
  479. //
  480. if (!FindNextFile(hLangDirFileSearch, &fdLangDir))
  481. {
  482. //
  483. // Exit the loop
  484. //
  485. break;
  486. }
  487. }
  488. if (INVALID_HANDLE_VALUE != hLangDirFileSearch)
  489. {
  490. FindClose(hLangDirFileSearch);
  491. //
  492. // Now try to remove the lang dir directory
  493. //
  494. //StringCchPrintf(szTemp, "%s\\%s", szCm32path, fdCm32.cFileName);
  495. RemoveDirectory(szTemp);
  496. }
  497. }
  498. }
  499. else
  500. {
  501. //StringCchPrintf(szTemp, "%s\\%s", szCm32path, fdCm32.cFileName);
  502. DeleteFile(szTemp);
  503. }
  504. //
  505. // Check to see if we have any more Files
  506. //
  507. if (!FindNextFile(hCm32FileSearch, &fdCm32))
  508. {
  509. if (INVALID_HANDLE_VALUE != hCm32FileSearch)
  510. {
  511. FindClose(hCm32FileSearch);
  512. }
  513. //
  514. // Now try to remove the cm32 directory
  515. //
  516. RemoveDirectory(szCm32path);
  517. //
  518. // Exit the loop
  519. //
  520. break;
  521. }
  522. }
  523. }
  524. //+---------------------------------------------------------------------------
  525. //
  526. // Function: DeleteProgramGroupWithLinks
  527. //
  528. // Purpose: Utility function to delete a given program group and its links.
  529. // Thus if you pass in the full path to a program group to delete,
  530. // the function does a findfirstfile to find and delete any links.
  531. // The function ignores sub-dirs.
  532. //
  533. //
  534. // Arguments: PCWSTR pszGroupPath - Full path to the program group to delete.
  535. //
  536. // Returns: Nothing
  537. //
  538. // Author: quintinb 6 Nov 1998
  539. //
  540. // Notes:
  541. void DeleteProgramGroupWithLinks(LPCTSTR pszGroupPath)
  542. {
  543. OutputDebugString("ADMINPAK: DeleteProgramGroupWithLinks...\n");
  544. HANDLE hLinkSearch;
  545. WIN32_FIND_DATA fdLinks;
  546. CHAR szLinkSearchString[MAX_PATH+1];
  547. CHAR szTemp[MAX_PATH+1];
  548. //StringCchPrintf(szLinkSearchString, "%s\\*.*", pszGroupPath);
  549. hLinkSearch = FindFirstFile(szLinkSearchString, &fdLinks);
  550. while (INVALID_HANDLE_VALUE != szLinkSearchString)
  551. {
  552. if (!(fdLinks.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  553. {
  554. //StringCchPrintf(szTemp, "%s\\%s", pszGroupPath, fdLinks.cFileName);
  555. DeleteFile(szTemp);
  556. }
  557. //
  558. // Check to see if we have any more Files
  559. //
  560. if (!FindNextFile(hLinkSearch, &fdLinks))
  561. {
  562. FindClose(hLinkSearch);
  563. //
  564. // Now try to remove the directory
  565. //
  566. RemoveDirectory(pszGroupPath);
  567. //
  568. // Exit the loop
  569. //
  570. break;
  571. }
  572. }
  573. }
  574. //+---------------------------------------------------------------------------
  575. //
  576. // Function: DeleteOldNtopLinks
  577. //
  578. // Purpose: Deletes the old links from the NT 4.0 Option Pack
  579. //
  580. //
  581. // Arguments: None
  582. //
  583. // Returns: Nothing
  584. //
  585. // Author: quintinb 6 Nov 1998
  586. //
  587. // Notes:
  588. void DeleteOldNtopLinks()
  589. {
  590. OutputDebugString("ADMINPAK: DeleteOldNtopLinks...\n");
  591. BOOL bResult = FALSE;
  592. //
  593. // First Delete the old NTOP4 Path
  594. //
  595. CHAR szGroup[MAX_PATH+1];
  596. CHAR szTemp[MAX_PATH+1];
  597. //
  598. // Get the CSIDL_COMMON_PROGRAMS value
  599. //
  600. bResult = SHGetSpecialFolderPath(NULL, szTemp, CSIDL_COMMON_PROGRAMS, FALSE);
  601. if ( bResult == TRUE )
  602. {
  603. //StringCchPrintf(szGroup, "%s\\%s\\%s", szTemp, OC_NTOP4_GROUPNAME, OC_ICS_GROUPNAME);
  604. DeleteProgramGroupWithLinks(szGroup);
  605. //StringCchPrintf(szGroup, "%s\\%s\\%s", szTemp, OC_PWS_GROUPNAME, OC_ICS_GROUPNAME);
  606. DeleteProgramGroupWithLinks(szGroup);
  607. }
  608. }
  609. //+---------------------------------------------------------------------------
  610. //
  611. // Function: DeleteIeakCmakLinks
  612. //
  613. // Purpose: Deletes the old links from the IEAK4 CMAK
  614. //
  615. //
  616. // Arguments: None
  617. //
  618. // Returns: Nothing
  619. //
  620. // Author: quintinb 6 Nov 1998
  621. //
  622. // Notes:
  623. void DeleteIeakCmakLinks()
  624. {
  625. OutputDebugString("ADMINPAK: DeleteIeakCmakLinks...\n");
  626. CHAR szUserDirRoot[MAX_PATH+1];
  627. CHAR szGroup[MAX_PATH+1];
  628. CHAR szTemp[MAX_PATH+1];
  629. CHAR szEnd[MAX_PATH+1];
  630. DWORD dwSize = _MAX_PATH;
  631. HRESULT res;
  632. //
  633. // Next Delete the old IEAK CMAK links
  634. //
  635. //
  636. // Get the Desktop directory and then remove the desktop part. This will give us the
  637. // root of the user directories.
  638. //
  639. BOOL bResult = SHGetSpecialFolderPath(NULL, szUserDirRoot, CSIDL_DESKTOPDIRECTORY, FALSE);
  640. if (bResult == TRUE)
  641. {
  642. //
  643. // Remove \\Desktop
  644. //
  645. CHAR* pszTemp = strrchr(szUserDirRoot, '\\');
  646. if (NULL == pszTemp)
  647. {
  648. return;
  649. }
  650. else
  651. {
  652. *pszTemp = '\0';
  653. }
  654. bResult = SHGetSpecialFolderPath(NULL, szTemp, CSIDL_PROGRAMS, FALSE);
  655. if (bResult == TRUE )
  656. {
  657. if (0 == _strnicmp(szUserDirRoot, szTemp, strlen(szUserDirRoot)))
  658. {
  659. res = StringCchCopy(szEnd, dwSize, &(szTemp[strlen(szUserDirRoot)]));
  660. if (res != S_OK)
  661. return;
  662. }
  663. }
  664. //
  665. // Remove \\<User Name>>
  666. //
  667. pszTemp = strrchr(szUserDirRoot, '\\');
  668. if (NULL == pszTemp)
  669. {
  670. return;
  671. }
  672. else
  673. {
  674. *pszTemp = '\0';
  675. }
  676. //
  677. // Now start searching for user dirs to delete the CMAK group from
  678. //
  679. CHAR szUserDirSearchString[MAX_PATH+1];
  680. HANDLE hUserDirSearch;
  681. WIN32_FIND_DATA fdUserDirs;
  682. //StringCchPrintf(szUserDirSearchString, "%s\\*.*", szUserDirRoot);
  683. hUserDirSearch = FindFirstFile(szUserDirSearchString, &fdUserDirs);
  684. while (INVALID_HANDLE_VALUE != hUserDirSearch)
  685. {
  686. if ((fdUserDirs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  687. (0 != _stricmp(fdUserDirs.cFileName, ".")) &&
  688. (0 != _stricmp(fdUserDirs.cFileName, "..")))
  689. {
  690. //StringCchPrintf(szGroup, "%s\\%s%s\\%s", szUserDirRoot, fdUserDirs.cFileName, szEnd, c_szCmakGroup);
  691. DeleteProgramGroupWithLinks(szGroup);
  692. }
  693. if (!FindNextFile(hUserDirSearch, &fdUserDirs))
  694. {
  695. FindClose(hUserDirSearch);
  696. //
  697. // Exit the loop
  698. //
  699. break;
  700. }
  701. }
  702. }
  703. }
  704. //+---------------------------------------------------------------------------
  705. //
  706. // Function: DeleteCmakRegKeys
  707. //
  708. // Purpose: Deletes the old Keys from Registery
  709. //
  710. //
  711. // Arguments: None
  712. //
  713. // Returns: Nothing
  714. //
  715. // Author: Darryl W. Wood 13 Jul 1999
  716. //
  717. // Notes:
  718. void DeleteCmakRegKeys()
  719. {
  720. OutputDebugString("ADMINPAK: DeleteCmakRegKeys...\n");
  721. LRESULT lResult;
  722. char szCmakUnInstRegPath[MAX_PATH] = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\CMAK";
  723. lResult = RegDeleteKey (
  724. HKEY_LOCAL_MACHINE, // handle to open key
  725. szCmakUnInstRegPath // address of name of subkey to delete
  726. );
  727. char szCmakAppRegPath[MAX_PATH] = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\CMAK.EXE";
  728. lResult = RegDeleteKey (
  729. HKEY_LOCAL_MACHINE, // handle to open key
  730. szCmakAppRegPath // address of name of subkey to delete
  731. );
  732. char szCmakAppUserInfoPath[MAX_PATH] = "SOFTWARE\\Microsoft\\Connection Manager Administration Kit\\User Info";
  733. lResult = RegDeleteKey (
  734. HKEY_LOCAL_MACHINE, // handle to open key
  735. szCmakAppUserInfoPath // address of name of subkey to delete
  736. );
  737. }
  738. //+---------------------------------------------------------------------------
  739. //
  740. // Function: CreateNewProfilesDirectory
  741. //
  742. // Author: Darryl W. Wood 13 Jul 1999
  743. //
  744. // Notes:
  745. void CreateNewProfilesDirectory( LPCTSTR pszNewProfilePath )
  746. {
  747. OutputDebugString("ADMINPAK: CreateNewProfilesDirectory...\n");
  748. char seps[] = "\\";
  749. char *token = NULL;
  750. char *szDriectoryString = NULL;
  751. szDriectoryString = new char[MAX_PATH * sizeof(char)];
  752. if ( NULL == szDriectoryString )
  753. {
  754. return;
  755. }
  756. char *szNewString = NULL;
  757. szNewString = new char[MAX_PATH * sizeof(char)];
  758. if ( NULL == szNewString )
  759. {
  760. if ( szDriectoryString != NULL )
  761. {
  762. delete [] szDriectoryString;
  763. }
  764. return;
  765. }
  766. HRESULT res;
  767. DWORD dwSize = _MAX_PATH;
  768. (void)StringCchCopy( szNewString, MAX_PATH * sizeof( char ), "" );
  769. res = StringCchCopy(szDriectoryString, dwSize, pszNewProfilePath);
  770. token = strtok( szDriectoryString, seps );
  771. res = StringCchCopy(szNewString, dwSize, token);
  772. res = StringCchCat(szNewString, dwSize, "\\");
  773. while( token != NULL && res == S_OK )
  774. {
  775. /* Get next token: */
  776. token = strtok( NULL, seps );
  777. if ( token == NULL ) {
  778. break;
  779. }
  780. res = StringCchCat(szNewString, dwSize, token);
  781. ::CreateDirectory(szNewString, NULL);
  782. res = StringCchCat(szNewString, dwSize, "\\");
  783. }
  784. delete [] szDriectoryString;
  785. delete [] szNewString;
  786. }
  787. HRESULT HrGetPBAPathIfInstalled(PSTR pszCpaPath, DWORD dwNumChars)
  788. {
  789. HRESULT hr;
  790. HKEY hKey;
  791. BOOL bFound = FALSE;
  792. // We need to see if PBA is installed or not. If it is then we want to
  793. // add back the PBA start menu link. If it isn't, then we want to do nothing
  794. // with PBA.
  795. //
  796. ZeroMemory(pszCpaPath, sizeof(CHAR)*dwNumChars);
  797. hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szDaoClientsPath, 0, KEY_READ, &hKey);
  798. if (SUCCEEDED(hr))
  799. {
  800. CHAR szCurrentValue[MAX_PATH+1];
  801. CHAR szCurrentData[MAX_PATH+1];
  802. DWORD dwValueSize = MAX_PATH;
  803. DWORD dwDataSize = MAX_PATH;
  804. DWORD dwType;
  805. DWORD dwIndex = 0;
  806. HRESULT res;
  807. while (ERROR_SUCCESS == RegEnumValue(hKey, dwIndex, szCurrentValue, &dwValueSize, NULL, &dwType,
  808. (LPBYTE)szCurrentData, &dwDataSize))
  809. {
  810. _strlwr(szCurrentValue);
  811. if (NULL != strstr(szCurrentValue, "pbadmin.exe"))
  812. {
  813. //
  814. // Then we have found the PBA path
  815. //
  816. CHAR* pszTemp = strrchr(szCurrentValue, '\\');
  817. if (NULL != pszTemp)
  818. {
  819. *pszTemp = '\0';
  820. res = StringCchCopy(pszCpaPath, dwDataSize ,szCurrentValue);
  821. bFound = TRUE;
  822. break;
  823. }
  824. }
  825. dwValueSize = MAX_PATH;
  826. dwDataSize = MAX_PATH;
  827. dwIndex++;
  828. }
  829. RegCloseKey(hKey);
  830. }
  831. if (!bFound)
  832. {
  833. // We didn't find PBA, so lets return S_FALSE
  834. //
  835. hr = S_FALSE;
  836. }
  837. else
  838. {
  839. hr = S_OK;
  840. }
  841. return hr;
  842. }
  843. BOOL GetAdminToolsFolder(PSTR pszAdminTools)
  844. {
  845. BOOL bReturn = FALSE;
  846. HRESULT res;
  847. DWORD dwSize = _MAX_PATH;
  848. if (pszAdminTools)
  849. {
  850. bReturn = SHGetSpecialFolderPath(NULL, pszAdminTools, CSIDL_COMMON_PROGRAMS, TRUE);
  851. if (bReturn)
  852. {
  853. // Now Append Administrative Tools
  854. //
  855. res = StringCchCat(pszAdminTools, dwSize, OC_ADMIN_TOOLS);
  856. if (res != S_OK)
  857. return FALSE;
  858. }
  859. }
  860. return bReturn;
  861. }
  862. HRESULT HrCreatePbaShortcut(PSTR pszCpaPath)
  863. {
  864. HRESULT hr = CoInitialize(NULL);
  865. DWORD dwSize = _MAX_PATH;
  866. if (SUCCEEDED(hr))
  867. {
  868. IShellLink *psl = NULL;
  869. hr = CoCreateInstance(CLSID_ShellLink, NULL,
  870. CLSCTX_INPROC_SERVER, //CLSCTX_LOCAL_SERVER,
  871. IID_IShellLink,
  872. (LPVOID*)&psl);
  873. if (SUCCEEDED(hr))
  874. {
  875. IPersistFile *ppf = NULL;
  876. // Set up the properties of the Shortcut
  877. //
  878. static const CHAR c_szPbAdmin[] = "\\pbadmin.exe";
  879. CHAR szPathToPbadmin[MAX_PATH+1] = {0};
  880. DWORD dwLen = strlen(c_szPbAdmin) + strlen(pszCpaPath) + 1;
  881. if (MAX_PATH >= dwLen)
  882. {
  883. // Set the Path to pbadmin.exe
  884. //
  885. hr = StringCchCopy(szPathToPbadmin, dwSize,pszCpaPath);
  886. hr = StringCchCat(szPathToPbadmin, dwSize,c_szPbAdmin);
  887. hr = psl->SetPath(szPathToPbadmin);
  888. if (SUCCEEDED(hr))
  889. {
  890. // Set the Description to Phone Book Administrator
  891. //
  892. hr = psl->SetDescription(OC_PBA_DESC);
  893. if (SUCCEEDED(hr))
  894. {
  895. hr = psl->QueryInterface(IID_IPersistFile,
  896. (LPVOID *)&ppf);
  897. if (SUCCEEDED(hr))
  898. {
  899. CHAR szAdminTools[MAX_PATH+1] = {0};
  900. if (GetAdminToolsFolder(szAdminTools))
  901. {
  902. // Create the link file.
  903. //
  904. long nLenString = 0;
  905. nLenString = strlen(szAdminTools) + 1;
  906. WCHAR wszAdminTools[MAX_PATH+1] = {0};
  907. mbstowcs( wszAdminTools, szAdminTools, nLenString );
  908. hr = ppf->Save(wszAdminTools, TRUE);
  909. }
  910. if ( ppf ) {
  911. ppf->Release();
  912. ppf = NULL;
  913. }
  914. }
  915. }
  916. }
  917. }
  918. if ( psl ) {
  919. psl->Release();
  920. psl = NULL;
  921. }
  922. }
  923. CoUninitialize();
  924. }
  925. return hr;
  926. }
  927. ///////////////////////////////////////////////////////////////////////////////////////////////
  928. ///////////////////////////////////////////////////////////////////////////////////////////////
  929. ///////////////////////////////////////////////////////////////////////////////////////////////
  930. ///////////////////////////////////////////////////////////////////////////////////////////////
  931. ///////////////////////////////////////////////////////////////////////////////////////////////
  932. ///////////////////////////////////////////////////////////////////////////////////////////////
  933. ///////////////////////////////////////////////////////////////////////////////////////////////
  934. ///////////////////////////////////////////////////////////////////////////////////////////////
  935. ///////////////////////////////////////////////////////////////////////////////////////////////
  936. ///////////////////////////////////////////////////////////////////////////////////////////////
  937. ///////////////////////////////////////////////////////////////////////////////////////////////
  938. ///////////////////////////////////////////////////////////////////////////////////////////////
  939. // MMC Detection Code
  940. //
  941. //Sets the MMCDETECTED property to True if MMC is found to be running on the machine
  942. extern "C" ADMINPAK_API int __stdcall fnDetectMMC(MSIHANDLE hInstall)
  943. {
  944. HWND lpWindowReturned = NULL;
  945. lpWindowReturned = FindWindowEx(NULL, NULL, "MMCMainFrame",NULL);
  946. if (lpWindowReturned != NULL)
  947. MsiSetProperty(hInstall, TEXT("MMCDETECTED"), "Yes"); //set property in MSI
  948. else
  949. MsiSetProperty(hInstall, TEXT("MMCDETECTED"), "No"); //set property in MSI
  950. return ERROR_SUCCESS;
  951. }
  952. ///////////////////////////////////////////////////////////////////////////////////////////////
  953. ///////////////////////////////////////////////////////////////////////////////////////////////
  954. ///////////////////////////////////////////////////////////////////////////////////////////////
  955. ///////////////////////////////////////////////////////////////////////////////////////////////
  956. ///////////////////////////////////////////////////////////////////////////////////////////////
  957. ///////////////////////////////////////////////////////////////////////////////////////////////
  958. ///////////////////////////////////////////////////////////////////////////////////////////////
  959. ///////////////////////////////////////////////////////////////////////////////////////////////
  960. ///////////////////////////////////////////////////////////////////////////////////////////////
  961. ///////////////////////////////////////////////////////////////////////////////////////////////
  962. ///////////////////////////////////////////////////////////////////////////////////////////////
  963. ///////////////////////////////////////////////////////////////////////////////////////////////
  964. // Admin Tools start menu folder Code
  965. //
  966. //Sets the AdminTools start menu folder to On
  967. extern "C" ADMINPAK_API int __stdcall fnAdminToolsFolderOn(MSIHANDLE hInstall)
  968. {
  969. DWORD dwError = NO_ERROR;
  970. HKEY hKey;
  971. LPCTSTR key = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
  972. LPCTSTR value = "Not set";
  973. DWORD data = 0;
  974. UNREFERENCED_PARAMETER( hInstall );
  975. //Open key to write to in the registry
  976. dwError = RegOpenKeyEx(HKEY_CURRENT_USER,key, 0, KEY_WRITE, &hKey );
  977. if ( dwError != ERROR_SUCCESS )
  978. return ERROR_INVALID_HANDLE;
  979. //Turn on the admin tools folder via their reg keys
  980. data = 2;
  981. value = "Start_AdminToolsRoot";
  982. dwError = RegSetValueEx(hKey, value, 0, REG_DWORD, (CONST BYTE *)&data, sizeof(data));
  983. if ( dwError != ERROR_SUCCESS )
  984. {
  985. RegCloseKey(hKey);
  986. return ERROR_INVALID_HANDLE;
  987. }
  988. data = 1;
  989. value = "StartMenuAdminTools";
  990. dwError = RegSetValueEx(hKey, value, 0, REG_DWORD, (CONST BYTE *)&data, sizeof(data));
  991. if ( dwError != ERROR_SUCCESS )
  992. {
  993. RegCloseKey(hKey);
  994. return ERROR_INVALID_HANDLE;
  995. }
  996. //Close key and exit
  997. RegCloseKey(hKey);
  998. return ERROR_SUCCESS;
  999. }
  1000. //Sets the AdminTools start menu folder to Off
  1001. extern "C" ADMINPAK_API int __stdcall fnAdminToolsFolderOff(MSIHANDLE hInstall)
  1002. {
  1003. DWORD dwError = NO_ERROR;
  1004. HKEY hKey;
  1005. const TCHAR key[] = TEXT( "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced" );
  1006. const TCHAR valueRoot[] = TEXT( "Start_AdminToolsRoot" );
  1007. const TCHAR valueMenu[] = TEXT( "StartMenuAdminTools" );
  1008. TCHAR lparam[] = TEXT( "Policy" );
  1009. DWORD data = 0;
  1010. DWORD_PTR dwResult = 0; //unused
  1011. UNREFERENCED_PARAMETER( hInstall );
  1012. //Open key to write to in the registry
  1013. dwError = RegOpenKeyEx(HKEY_CURRENT_USER, key, 0, KEY_WRITE, &hKey );
  1014. if ( dwError != ERROR_SUCCESS )
  1015. return ERROR_INVALID_HANDLE;
  1016. //Turn off the admin tools folder via their reg keys
  1017. // value = "Start_AdminToolsRoot";
  1018. data = 0;
  1019. dwError = RegSetValueEx(hKey, valueRoot, 0, REG_DWORD, (CONST BYTE *)&data, sizeof(data));
  1020. if ( dwError != ERROR_SUCCESS )
  1021. {
  1022. RegCloseKey(hKey);
  1023. return ERROR_INVALID_HANDLE;
  1024. }
  1025. // value = "StartMenuAdminTools";
  1026. data = 0;
  1027. dwError = RegSetValueEx(hKey, valueMenu, 0, REG_DWORD, (CONST BYTE *)&data, sizeof(data));
  1028. if ( dwError != ERROR_SUCCESS )
  1029. {
  1030. RegCloseKey(hKey);
  1031. return ERROR_INVALID_HANDLE;
  1032. }
  1033. //Close key and exit
  1034. RegCloseKey(hKey);
  1035. //Undocumented API call to force a redraw of the start menu to remove the admin tools folder without logging off or having the user have to manually "apply" the changes to the start menu
  1036. SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) lparam , SMTO_ABORTIFHUNG, 1000, &dwResult );
  1037. return ERROR_SUCCESS;
  1038. }
  1039. ///////////////////////////////////////////////////////////////////////////////////////////////
  1040. ///////////////////////////////////////////////////////////////////////////////////////////////
  1041. ///////////////////////////////////////////////////////////////////////////////////////////////
  1042. ///////////////////////////////////////////////////////////////////////////////////////////////
  1043. ///////////////////////////////////////////////////////////////////////////////////////////////
  1044. ///////////////////////////////////////////////////////////////////////////////////////////////
  1045. ///////////////////////////////////////////////////////////////////////////////////////////////
  1046. ///////////////////////////////////////////////////////////////////////////////////////////////
  1047. ///////////////////////////////////////////////////////////////////////////////////////////////
  1048. ///////////////////////////////////////////////////////////////////////////////////////////////
  1049. ///////////////////////////////////////////////////////////////////////////////////////////////
  1050. ///////////////////////////////////////////////////////////////////////////////////////////////
  1051. //AdminpakBackup table handling Code
  1052. //
  1053. //Backup files from the AdminpakBackup table
  1054. extern "C" ADMINPAK_API int __stdcall fnBackupAdminpakBackupTable(MSIHANDLE hInstall)
  1055. {
  1056. DWORD dwLength = MAX_PATH; //Length of string to return from MSI
  1057. DWORD dwError = NO_ERROR; //Error variable
  1058. TCHAR szDir[MAX_PATH]; //Directory read from the MSI
  1059. TCHAR szDirFromMSI[MAX_PATH]; //Directory read from Adminbackup table
  1060. TCHAR szFileToBackup[MAX_PATH]; //File name to backup
  1061. TCHAR szBackupFileName[MAX_PATH]; //Backed up file name
  1062. TCHAR szFileToBackupFromMSI[MAX_PATH]; //File name to backup from MSI
  1063. TCHAR szBackupFileNameFromMSI[MAX_PATH]; //Backed up file name
  1064. HRESULT res;
  1065. PMSIHANDLE hView; //MSI view handle
  1066. PMSIHANDLE hRecord; //MSI record handle
  1067. PMSIHANDLE hDatabase; //MSI database handle
  1068. TCHAR szSQL[MAX_PATH]; //SQL to return table from MSI
  1069. res = StringCchCopy(szSQL, dwLength,TEXT("SELECT * FROM `AdminpackBackup`"));
  1070. // Get a handle on the MSI database
  1071. hDatabase = MsiGetActiveDatabase(hInstall);
  1072. if( hDatabase == 0 )
  1073. return ERROR_INVALID_HANDLE;
  1074. //Get a view of our table in the MSI
  1075. dwError = MsiDatabaseOpenView(hDatabase, szSQL, &hView );
  1076. if( dwError == ERROR_SUCCESS )
  1077. dwError = MsiViewExecute(hView, NULL );
  1078. // If no errors, get our records
  1079. if( dwError != ERROR_SUCCESS )
  1080. {
  1081. return ERROR_INVALID_HANDLE;
  1082. }
  1083. else
  1084. {
  1085. //Loop through records in the AdminpakBackup table
  1086. while(MsiViewFetch(hView, &hRecord ) == ERROR_SUCCESS )
  1087. {
  1088. dwError = MsiRecordGetString(hRecord, BACKUPFILENAME, szBackupFileNameFromMSI , &dwLength);
  1089. if( dwError != ERROR_SUCCESS )
  1090. return ERROR_INVALID_HANDLE;
  1091. dwLength = MAX_PATH;
  1092. dwError = MsiRecordGetString(hRecord, ORIGINALFILENAME, szFileToBackupFromMSI , &dwLength);
  1093. if( dwError != ERROR_SUCCESS )
  1094. return ERROR_INVALID_HANDLE;
  1095. dwLength = MAX_PATH;
  1096. dwError = MsiRecordGetString(hRecord, BACKUPDIRECTORY, szDirFromMSI , &dwLength);
  1097. if( dwError != ERROR_SUCCESS )
  1098. return ERROR_INVALID_HANDLE;
  1099. dwLength = MAX_PATH;
  1100. dwError = MsiGetProperty( hInstall, TEXT(szDirFromMSI), szDir, &dwLength );
  1101. if( dwError != ERROR_SUCCESS )
  1102. return ERROR_INVALID_HANDLE;
  1103. dwLength = MAX_PATH;
  1104. //Build up the paths for the file to backup
  1105. res = StringCchCopy(szFileToBackup, dwLength ,szDir);
  1106. res = StringCchCat(szFileToBackup, dwLength, szFileToBackupFromMSI);
  1107. res = StringCchCopy(szBackupFileName, dwLength, szDir);
  1108. res = StringCchCat(szBackupFileName, dwLength, szBackupFileNameFromMSI);
  1109. //Perform backup
  1110. //We know MoveFileEx is inseucure due to ACL's, but we are moving to same directory and planing on moving file back on uninstall, so we should be OK as far as ACL's are concearned
  1111. if (res == S_OK)
  1112. {
  1113. dwError = MoveFileEx(szFileToBackup,szBackupFileName, MOVEFILE_WRITE_THROUGH);
  1114. }
  1115. if( dwError == 0 )
  1116. {
  1117. if ( GetLastError() == ERROR_FILE_NOT_FOUND )
  1118. {
  1119. // ignore this error
  1120. }
  1121. else
  1122. {
  1123. // even in this case, we will ignore this error
  1124. // this is because, anyhow, the failure of this action
  1125. // will not stop from MSI installing the package --
  1126. // so, practically, there is no meaning in stoping this action in middle
  1127. //
  1128. // return ERROR_INVALID_HANDLE;
  1129. //
  1130. }
  1131. }
  1132. dwError = MsiCloseHandle(hRecord); //Close record
  1133. if( dwError != ERROR_SUCCESS )
  1134. return ERROR_INVALID_HANDLE;
  1135. }
  1136. }
  1137. dwError = MsiViewClose( hView ); //Close view
  1138. if( dwError != ERROR_SUCCESS )
  1139. return ERROR_INVALID_HANDLE;
  1140. dwError = MsiCloseHandle( hDatabase ); //Close Database
  1141. if( dwError != ERROR_SUCCESS )
  1142. return ERROR_INVALID_HANDLE;
  1143. return ERROR_SUCCESS;
  1144. }
  1145. //Restores files specified in the AdminpakBackup table, called during uninstall...
  1146. extern "C" ADMINPAK_API int __stdcall fnRestoreAdminpakBackupTable(MSIHANDLE hInstall)
  1147. {
  1148. DWORD dwLength = MAX_PATH; //Length of string to return from MSI
  1149. DWORD dwError = ERROR_SUCCESS; //Error variable
  1150. HRESULT res;
  1151. TCHAR szDir[MAX_PATH]; //Directory read from the MSI
  1152. TCHAR szDirFromMSI[MAX_PATH]; //Directory read from Adminbackup table
  1153. TCHAR szFileToRestore[MAX_PATH]; //File name to restore
  1154. TCHAR szBackupFileName[MAX_PATH]; //Backed up file name
  1155. TCHAR szFileToRestoreFromMSI[MAX_PATH]; //File name to restore
  1156. TCHAR szBackupFileNameFromMSI[MAX_PATH]; //Backed up file name
  1157. TCHAR szSQL[MAX_PATH]; //SQL to return table from MSI
  1158. res = StringCchCopy(szSQL, dwLength, TEXT("SELECT * FROM `AdminpackBackup`"));
  1159. PMSIHANDLE hView; //MSI view handle
  1160. PMSIHANDLE hRecord; //MSI record handle
  1161. PMSIHANDLE hDatabase; //MSI database handle
  1162. // Get a handle on the MSI database
  1163. hDatabase = MsiGetActiveDatabase(hInstall);
  1164. if( hDatabase == 0 )
  1165. return ERROR_INVALID_HANDLE;
  1166. //Get a view of our table in the MSI
  1167. dwError = MsiDatabaseOpenView(hDatabase, szSQL, &hView );
  1168. if( dwError == ERROR_SUCCESS )
  1169. dwError = MsiViewExecute(hView, NULL );
  1170. // If no errors, get our records
  1171. if( dwError != ERROR_SUCCESS )
  1172. {
  1173. return ERROR_INVALID_HANDLE;
  1174. }
  1175. else
  1176. {
  1177. //Loop through records in the AdminpakBackup table
  1178. while(MsiViewFetch(hView, &hRecord ) == ERROR_SUCCESS )
  1179. {
  1180. dwError = MsiRecordGetString(hRecord, ORIGINALFILENAME, szBackupFileNameFromMSI , &dwLength);
  1181. if( dwError != ERROR_SUCCESS )
  1182. return ERROR_INVALID_HANDLE;
  1183. dwLength = MAX_PATH;
  1184. dwError = MsiRecordGetString(hRecord, BACKUPFILENAME, szFileToRestoreFromMSI , &dwLength);
  1185. if( dwError != ERROR_SUCCESS )
  1186. return ERROR_INVALID_HANDLE;
  1187. dwLength = MAX_PATH;
  1188. dwError = MsiRecordGetString(hRecord, BACKUPDIRECTORY, szDirFromMSI , &dwLength);
  1189. if( dwError != ERROR_SUCCESS )
  1190. return ERROR_INVALID_HANDLE;
  1191. dwLength = MAX_PATH;
  1192. dwError = MsiGetProperty( hInstall, TEXT(szDirFromMSI), szDir, &dwLength );
  1193. if( dwError != ERROR_SUCCESS )
  1194. return ERROR_INVALID_HANDLE;
  1195. dwLength = MAX_PATH;
  1196. //Build up the paths for the file to restore
  1197. res = StringCchCopy(szFileToRestore, dwLength, szDir);
  1198. res = StringCchCat(szFileToRestore, dwLength, szBackupFileNameFromMSI);
  1199. res = StringCchCopy(szBackupFileName, dwLength, szDir);
  1200. res = StringCchCat(szBackupFileName, dwLength, szFileToRestoreFromMSI);
  1201. //Perform restore
  1202. dwError = MoveFileEx(szBackupFileName, szFileToRestore, MOVEFILE_REPLACE_EXISTING); //Restore the file
  1203. if( dwError == 0 )
  1204. {
  1205. if ( GetLastError() == ERROR_FILE_NOT_FOUND )
  1206. {
  1207. // ignore this error
  1208. }
  1209. else
  1210. {
  1211. // even in this case, we will ignore this error
  1212. // this is because, anyhow, the failure of this action
  1213. // will not stop from MSI installing the package --
  1214. // so, practically, there is no meaning in stoping this action in middle
  1215. //
  1216. // return ERROR_INVALID_HANDLE;
  1217. //
  1218. }
  1219. }
  1220. dwError = MsiCloseHandle(hRecord); //Close Record
  1221. if( dwError != ERROR_SUCCESS )
  1222. return ERROR_INVALID_HANDLE;
  1223. }
  1224. }
  1225. dwError = MsiViewClose(hView); //Close View
  1226. if( dwError != ERROR_SUCCESS )
  1227. return ERROR_INVALID_HANDLE;
  1228. dwError = MsiCloseHandle(hDatabase); //Close Database
  1229. if( dwError != ERROR_SUCCESS )
  1230. return ERROR_INVALID_HANDLE;
  1231. return ERROR_SUCCESS;
  1232. }
  1233. // check whether the OEM code page and SYSTEM code are same or not
  1234. extern "C" ADMINPAK_API int __stdcall fnNativeOSLanguage( MSIHANDLE hInstall )
  1235. {
  1236. // local variables
  1237. HRESULT hr = S_OK;
  1238. LANGID langOEM = 0;
  1239. WCHAR wszLanguageCode[ 10 ] = L"\0";
  1240. // get the OEM code page
  1241. langOEM = GetSystemDefaultUILanguage();
  1242. // convert the numeric value into string format
  1243. hr = StringCchPrintfW( wszLanguageCode, 10, L"%d", langOEM );
  1244. if ( FAILED( hr ) )
  1245. {
  1246. return ERROR_INVALID_HANDLE;
  1247. }
  1248. // save the native OS language information
  1249. MsiSetPropertyW( hInstall, L"NativeOSLanguage", wszLanguageCode );
  1250. // return success
  1251. return ERROR_SUCCESS;
  1252. }
  1253. void fnDeleteShortcut(MSIHANDLE, TCHAR[_MAX_PATH]);
  1254. //Cleans up after a Win2k adminpak upgrade as Win2k adminpak leaves behind several shortcuts that we need to clean up after
  1255. extern "C" ADMINPAK_API int __stdcall fnCleanW2KUpgrade( MSIHANDLE hInstall )
  1256. {
  1257. //Call fnDeleteShortcut with the name of the shortcut you want to delete
  1258. fnDeleteShortcut(hInstall, "Internet Services Manager");
  1259. fnDeleteShortcut(hInstall, "Routing and Remote Access");
  1260. fnDeleteShortcut(hInstall, "Distributed File System");
  1261. fnDeleteShortcut(hInstall, "Local Security Policy");
  1262. // return success
  1263. return ERROR_SUCCESS;
  1264. }
  1265. //Actually does the shortcut deletion
  1266. void fnDeleteShortcut(MSIHANDLE hInstall, TCHAR LinkName[])
  1267. {
  1268. HRESULT hr = S_OK;
  1269. TCHAR buf[_MAX_PATH]; //shortcut path/name buffer
  1270. DWORD dwLength = _MAX_PATH; //Length of string to return from MSI
  1271. LPITEMIDLIST pidl; //used to get admin tools shortcut path
  1272. UNREFERENCED_PARAMETER( hInstall );
  1273. //get admin tools shortcut folder
  1274. hr = SHGetSpecialFolderLocation( NULL, CSIDL_COMMON_ADMINTOOLS, &pidl );
  1275. SHGetPathFromIDList(pidl, buf);
  1276. //append shortcut name and extention
  1277. hr = StringCchCat( buf, dwLength, "\\" );
  1278. hr = StringCchCat( buf, dwLength, LinkName );
  1279. hr = StringCchCat( buf, dwLength, ".lnk");
  1280. //delete the shortcut and return
  1281. DeleteFile( buf );
  1282. }
  1283. BOOL TranslateVersionString( LPCWSTR pwszVersion, PTVERSION pVersion )
  1284. {
  1285. // local variables
  1286. DWORD dwLoop = 0;
  1287. LONG lPosition = 0;
  1288. CHString strTemp;
  1289. CHString strVersion;
  1290. CHString strVersionField;
  1291. LPWSTR pwszTemp = NULL;
  1292. LPWSTR pwszNumber = NULL;
  1293. DWORD dwNumbers[ 4 ];
  1294. // check the input parameters
  1295. if ( pVersion == NULL || pwszVersion == NULL )
  1296. {
  1297. return FALSE;
  1298. }
  1299. // init the version struct to zero's
  1300. ZeroMemory( pVersion, sizeof( TVERSION ) );
  1301. ZeroMemory( dwNumbers, 4 * sizeof( DWORD ) );
  1302. try
  1303. {
  1304. // get the version info into the class variable
  1305. strVersion = pwszVersion;
  1306. // trim the string
  1307. strVersion.TrimLeft();
  1308. strVersion.TrimRight();
  1309. // cut the string till the first space we encountered in it
  1310. lPosition = strVersion.Find( L' ' );
  1311. if ( lPosition != -1 )
  1312. {
  1313. strTemp = strVersion.Mid( 0, lPosition );
  1314. strVersion = strTemp;
  1315. }
  1316. // we need to get 4 parts from the version string
  1317. for ( dwLoop = 0; dwLoop < 4; dwLoop++ )
  1318. {
  1319. lPosition = strVersion.Find( L'.' );
  1320. if ( lPosition == -1 )
  1321. {
  1322. // this might be the last number
  1323. if ( strVersion.GetLength() == 0 )
  1324. {
  1325. break;
  1326. }
  1327. else
  1328. {
  1329. strVersionField = strVersion;
  1330. strVersion.Empty();
  1331. }
  1332. }
  1333. else
  1334. {
  1335. strVersionField = strVersion.Mid( 0, lPosition );
  1336. strTemp = strVersion.Mid( lPosition + 1 );
  1337. strVersion = strTemp;
  1338. }
  1339. // get the version field internal buffer
  1340. // NOTE: assuming no. of digits in a version string is never going to larger than 10 digits
  1341. pwszNumber = strVersionField.GetBuffer( 10 );
  1342. if ( pwszNumber == NULL )
  1343. {
  1344. return FALSE;
  1345. }
  1346. // convert the number
  1347. dwNumbers[ dwLoop ] = wcstoul( pwszNumber, &pwszTemp, 10 );
  1348. //
  1349. // check the validity of the number
  1350. //
  1351. if ( errno == ERANGE || (pwszTemp != NULL && lstrlenW( pwszTemp ) != 0 ))
  1352. {
  1353. strVersionField.ReleaseBuffer( -1 );
  1354. return FALSE;
  1355. }
  1356. // release the buffer
  1357. strVersionField.ReleaseBuffer( -1 );
  1358. }
  1359. // check the no. of loops that are done -- it the loops are not equal to 3, error
  1360. // we dont care whether we got the sub-revision or not -- so, we are not checking for 4 here
  1361. if ( dwLoop < 3 || strVersion.GetLength() != 0 )
  1362. {
  1363. return FALSE;
  1364. }
  1365. // everything went well
  1366. pVersion->dwMajor = dwNumbers[ 0 ];
  1367. pVersion->dwMinor = dwNumbers[ 1 ];
  1368. pVersion->dwRevision = dwNumbers[ 2 ];
  1369. pVersion->dwSubRevision = dwNumbers[ 3 ];
  1370. // return
  1371. return TRUE;
  1372. }
  1373. catch( ... )
  1374. {
  1375. return FALSE;
  1376. }
  1377. }
  1378. LONG CheckFileVersion( LPCWSTR pwszFileName,
  1379. LPCWSTR pwszRequiredInternalName,
  1380. LPCWSTR pwszRequiredFileVersion )
  1381. {
  1382. // local variables
  1383. DWORD dw = 0;
  1384. UINT dwSize = 0;
  1385. UINT dwTranslateSize = 0;
  1386. LPVOID pVersionInfo = NULL;
  1387. PTTRANSLATE pTranslate = NULL;
  1388. LPCWSTR pwszFileVersion = NULL;
  1389. LPCWSTR pwszInternalName = NULL;
  1390. TVERSION verFileVersion;
  1391. TVERSION verRequiredFileVersion;
  1392. // check the input
  1393. // NOTE: we dont care whether "pwszRequiredInternalName" is passed or not
  1394. if ( pwszFileName == NULL || pwszRequiredFileVersion == NULL )
  1395. {
  1396. return translateError;
  1397. }
  1398. // translate the required file version string into TVERSION struct
  1399. if ( TranslateVersionString( pwszRequiredFileVersion, &verRequiredFileVersion ) == FALSE )
  1400. {
  1401. // version string passed is invalid
  1402. return translateError;
  1403. }
  1404. // init
  1405. dw = 0;
  1406. dwSize = _MAX_PATH;
  1407. // get the version information size
  1408. dwSize = GetFileVersionInfoSizeW( pwszFileName, 0 );
  1409. if ( dwSize == 0 )
  1410. {
  1411. // tool might have encountered error (or)
  1412. // tool doesn't have version information
  1413. // but version information is mandatory for us
  1414. // so, just exit
  1415. if ( GetLastError() == NO_ERROR )
  1416. {
  1417. SetLastError( ERROR_INVALID_PARAMETER );
  1418. return translateError;
  1419. }
  1420. // ...
  1421. return translateError;
  1422. }
  1423. // allocate memory for the version resource
  1424. // take some 10 bytes extra -- for safety purposes
  1425. dwSize += 10;
  1426. pVersionInfo = new BYTE[ dwSize ];
  1427. if ( pVersionInfo == NULL )
  1428. {
  1429. return translateError;
  1430. }
  1431. // now get the version information
  1432. if ( GetFileVersionInfoW( pwszFileName, 0, dwSize, pVersionInfo ) == FALSE )
  1433. {
  1434. delete [] pVersionInfo;
  1435. return translateError;
  1436. }
  1437. // get the translation info
  1438. if ( VerQueryValueW( pVersionInfo,
  1439. L"\\VarFileInfo\\Translation",
  1440. (LPVOID*) &pTranslate, &dwTranslateSize ) == FALSE )
  1441. {
  1442. delete [] pVersionInfo;
  1443. return translateError;
  1444. }
  1445. // try to get the internal name of the tool for each language and code page.
  1446. pwszFileVersion = NULL;
  1447. pwszInternalName = NULL;
  1448. for( dw = 0; dw < ( dwTranslateSize / sizeof( TTRANSLATE ) ); dw++ )
  1449. {
  1450. try
  1451. {
  1452. //
  1453. // prepare the format string to get the localized the version info
  1454. //
  1455. CHString strBuffer;
  1456. LPWSTR pwszBuffer = NULL;
  1457. //
  1458. // file version
  1459. strBuffer.Format(
  1460. L"\\StringFileInfo\\%04x%04x\\FileVersion",
  1461. pTranslate[ dw ].wLanguage, pTranslate[ dw ].wCodePage );
  1462. // retrieve file description for language and code page "i".
  1463. pwszBuffer = strBuffer.LockBuffer();
  1464. if ( VerQueryValueW( pVersionInfo, pwszBuffer,
  1465. (LPVOID*) &pwszFileVersion, &dwSize ) == FALSE )
  1466. {
  1467. // we cannot decide the failure based on the result of this
  1468. // function failure -- we will decide about this
  1469. // after terminating from the 'for' loop
  1470. // for now, make the pwszFileVersion to NULL -- this will
  1471. // enable us to decide the result
  1472. pwszFileVersion = NULL;
  1473. }
  1474. // release the earlier access buffer
  1475. strBuffer.UnlockBuffer();
  1476. //
  1477. // internal name
  1478. strBuffer.Format(
  1479. L"\\StringFileInfo\\%04x%04x\\InternalName",
  1480. pTranslate[ dw ].wLanguage, pTranslate[ dw ].wCodePage );
  1481. // retrieve file description for language and code page "i".
  1482. pwszBuffer = strBuffer.LockBuffer();
  1483. if ( VerQueryValueW( pVersionInfo, pwszBuffer,
  1484. (LPVOID*) &pwszInternalName, &dwSize ) == FALSE )
  1485. {
  1486. // we cannot decide the failure based on the result of this
  1487. // function failure -- we will decide about this
  1488. // after terminating from the 'for' loop
  1489. // for now, make the pwszInternalName to NULL -- this will
  1490. // enable us to decide the result
  1491. pwszInternalName = NULL;
  1492. }
  1493. // release the earlier access buffer
  1494. strBuffer.UnlockBuffer();
  1495. // check whether we got the information that we are looking for or not
  1496. if ( pwszInternalName != NULL && pwszFileVersion != NULL )
  1497. {
  1498. // we got the information
  1499. break;
  1500. }
  1501. }
  1502. catch( ... )
  1503. {
  1504. // do not return -- we might miss the cleanup
  1505. // so just break from the loop and rest will be taken care
  1506. // outside the loop
  1507. pwszFileVersion = NULL;
  1508. pwszInternalName = NULL;
  1509. break;
  1510. }
  1511. }
  1512. // check whether we got the information or we need or not
  1513. if ( pwszInternalName == NULL || pwszFileVersion == NULL )
  1514. {
  1515. delete [] pVersionInfo;
  1516. return translateError;
  1517. }
  1518. // check the internal name -- this is important to make sure that
  1519. // user is not trying to cheat the installation
  1520. if ( pwszRequiredInternalName != NULL )
  1521. {
  1522. if ( CompareStringW( LOCALE_INVARIANT, NORM_IGNORECASE,
  1523. pwszInternalName, -1, pwszRequiredInternalName, -1 ) != CSTR_EQUAL )
  1524. {
  1525. // installation is being cheated
  1526. delete [] pVersionInfo;
  1527. return translateWrongFile;
  1528. }
  1529. }
  1530. //
  1531. // translate the version string
  1532. if ( TranslateVersionString( pwszFileVersion, &verFileVersion ) == FALSE )
  1533. {
  1534. delete [] pVersionInfo;
  1535. return translateError;
  1536. }
  1537. // we are dont with pVersionInfo -- release the memory
  1538. delete [] pVersionInfo;
  1539. //
  1540. // now compare the file version with the required file version
  1541. // major version
  1542. if ( verFileVersion.dwMajor == verRequiredFileVersion.dwMajor )
  1543. {
  1544. // need to proceed with checking minor version
  1545. }
  1546. else if ( verFileVersion.dwMajor < verRequiredFileVersion.dwMajor )
  1547. {
  1548. return translateLesser;
  1549. }
  1550. else if ( verFileVersion.dwMajor > verRequiredFileVersion.dwMajor )
  1551. {
  1552. return translateGreater;
  1553. }
  1554. // minor version
  1555. if ( verFileVersion.dwMinor == verRequiredFileVersion.dwMinor )
  1556. {
  1557. // need to proceed with checking revision (build number)
  1558. }
  1559. else if ( verFileVersion.dwMinor < verRequiredFileVersion.dwMinor )
  1560. {
  1561. return translateLesser;
  1562. }
  1563. else if ( verFileVersion.dwMinor > verRequiredFileVersion.dwMinor )
  1564. {
  1565. return translateGreater;
  1566. }
  1567. // revision (build number)
  1568. if ( verFileVersion.dwRevision == verRequiredFileVersion.dwRevision )
  1569. {
  1570. // need to proceed with checking sub-revision (QFE / SP)
  1571. }
  1572. else if ( verFileVersion.dwRevision < verRequiredFileVersion.dwRevision )
  1573. {
  1574. return translateLesser;
  1575. }
  1576. else if ( verFileVersion.dwRevision > verRequiredFileVersion.dwRevision )
  1577. {
  1578. return translateGreater;
  1579. }
  1580. // sub-revision (QFE / SP)
  1581. if ( verFileVersion.dwSubRevision == verRequiredFileVersion.dwSubRevision )
  1582. {
  1583. // done -- version's matched
  1584. return translateEqual;
  1585. }
  1586. else if ( verFileVersion.dwSubRevision < verRequiredFileVersion.dwSubRevision )
  1587. {
  1588. return translateLesser;
  1589. }
  1590. else if ( verFileVersion.dwSubRevision > verRequiredFileVersion.dwSubRevision )
  1591. {
  1592. return translateGreater;
  1593. }
  1594. // return -- we should not come to this point -- if reached -- error
  1595. return translateError;
  1596. }
  1597. // verify the existence of the QFE
  1598. extern "C" ADMINPAK_API int __stdcall fnCheckForQFE( MSIHANDLE hInstall )
  1599. {
  1600. // local variables
  1601. CHString strFile;
  1602. CHString strSystemDirectory;
  1603. // get the path reference to the "system32" directory
  1604. // NOTE: we cannot proceed if we cant get the path to the "system32" directory
  1605. if ( PropertyGet_String( hInstall, L"SystemFolder", strSystemDirectory ) == FALSE )
  1606. {
  1607. return ERROR_INVALID_HANDLE;
  1608. }
  1609. // form the path
  1610. strFile.Format( L"%s%s", strSystemDirectory, L"dsprop.dll" );
  1611. // now check ...
  1612. switch( CheckFileVersion( strFile, L"ShADprop", L"5.1.2600.101" ) )
  1613. {
  1614. case translateEqual:
  1615. case translateGreater:
  1616. {
  1617. // set the native OS language information
  1618. MsiSetPropertyW( hInstall, L"QFE_DSPROP", L"Yes" );
  1619. break;
  1620. }
  1621. default:
  1622. // do nothing
  1623. break;
  1624. }
  1625. // return
  1626. return ERROR_SUCCESS;
  1627. }