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.

584 lines
16 KiB

  1. // ---------------------------------------------------------------------------
  2. // DETECT.CPP
  3. // ---------------------------------------------------------------------------
  4. // Copyright (c) 1999 Microsoft Corporation
  5. //
  6. // Helper functions to detect installed versions of WAB / OE
  7. //
  8. // ---------------------------------------------------------------------------
  9. #include "pch.hxx"
  10. #include <strings.h>
  11. #include "main.h"
  12. #include "detect.h"
  13. const LPCTSTR c_szVers[] = { c_szVERnone, c_szVER1_0, c_szVER1_1, c_szVER4_0, c_szVER5B1 };
  14. const LPCTSTR c_szBlds[] = { c_szBLDnone, c_szBLD1_0, c_szBLD1_1, c_szBLD4_0, c_szBLD5B1 };
  15. #define FORCE_DEL(_sz) { \
  16. if ((dwAttr = GetFileAttributes(_sz)) != 0xFFFFFFFF) \
  17. { \
  18. SetFileAttributes(_sz, dwAttr & ~FILE_ATTRIBUTE_READONLY); \
  19. DeleteFile(_sz); \
  20. } }
  21. /*******************************************************************
  22. NAME: TranslateVers
  23. SYNOPSIS: Takes 5.0B1 versions and translates to bld numbers
  24. ********************************************************************/
  25. BOOL TranslateVers(OUT SETUPVER *psv,
  26. OUT LPTSTR pszVer,
  27. IN int cch)
  28. {
  29. BOOL fTranslated = FALSE;
  30. // Validate params
  31. Assert(pszVer);
  32. // Initialize out params
  33. *psv = VER_NONE;
  34. // Special case builds 624-702
  35. if (!lstrcmp(pszVer, c_szVER5B1old))
  36. {
  37. StrCpyN(pszVer, c_szBlds[VER_5_0_B1], cch);
  38. *psv = VER_5_0_B1;
  39. fTranslated = TRUE;
  40. }
  41. else
  42. {
  43. for (int i = VER_NONE; i < VER_5_0; i++)
  44. {
  45. if (!lstrcmp(c_szVers[i], pszVer))
  46. {
  47. StrCpyN(pszVer, c_szBlds[i], cch);
  48. *psv = (SETUPVER)i;
  49. fTranslated = TRUE;
  50. break;
  51. }
  52. }
  53. }
  54. return fTranslated;
  55. }
  56. /*******************************************************************
  57. NAME: ConvertStrToVer
  58. ********************************************************************/
  59. void ConvertStrToVer(IN LPCSTR pszStr,
  60. OUT WORD *pwVer)
  61. {
  62. int i;
  63. // Validate Params
  64. Assert(pszStr);
  65. Assert(pwVer);
  66. // Initialize out param
  67. ZeroMemory(pwVer, 4 * sizeof(*pwVer));
  68. for (i=0; i<4; i++)
  69. {
  70. while (*pszStr && (*pszStr != ',') && (*pszStr != '.'))
  71. {
  72. pwVer[i] *= 10;
  73. pwVer[i] = (WORD)(pwVer[i] + (*pszStr - '0'));
  74. pszStr++;
  75. }
  76. if (*pszStr)
  77. pszStr++;
  78. }
  79. return;
  80. }
  81. /*******************************************************************
  82. NAME: ConvertVerToEnum
  83. ********************************************************************/
  84. SETUPVER ConvertVerToEnum(IN WORD *pwVer)
  85. {
  86. SETUPVER sv;
  87. // Validate params
  88. Assert(pwVer);
  89. switch (pwVer[0])
  90. {
  91. case 0:
  92. sv = VER_NONE;
  93. break;
  94. case 1:
  95. if (0 == pwVer[1])
  96. sv = VER_1_0;
  97. else
  98. sv = VER_1_1;
  99. break;
  100. case 4:
  101. sv = VER_4_0;
  102. break;
  103. case 5:
  104. sv = VER_5_0;
  105. break;
  106. default:
  107. sv = VER_MAX;
  108. }
  109. return sv;
  110. }
  111. /*******************************************************************
  112. NAME: GetASetupVer
  113. ********************************************************************/
  114. BOOL GetASetupVer(IN LPCTSTR pszGUID,
  115. OUT WORD *pwVer, // OPTIONAL
  116. OUT LPTSTR pszVer, // OPTIONAL
  117. IN int cch) // OPTIONAL
  118. {
  119. BOOL fInstalled = FALSE;
  120. DWORD dwValue, cb;
  121. HKEY hkey;
  122. TCHAR szPath[MAX_PATH], szVer[64];
  123. // Validate Params
  124. Assert(pszGUID);
  125. // Initialize out params
  126. if (pszVer)
  127. pszVer[0] = 0;
  128. if (pwVer)
  129. ZeroMemory(pwVer, 4 * sizeof(*pwVer));
  130. wnsprintf(szPath, ARRAYSIZE(szPath), c_szPathFileFmt, c_szRegASetup, pszGUID);
  131. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szPath, 0, KEY_QUERY_VALUE, &hkey))
  132. {
  133. cb = sizeof(dwValue);
  134. if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szIsInstalled, 0, NULL, (LPBYTE)&dwValue, &cb))
  135. {
  136. if (1 == dwValue)
  137. {
  138. cb = sizeof(szVer);
  139. if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szValueVersion, 0, NULL, (LPBYTE)szVer, &cb))
  140. {
  141. if (pwVer)
  142. ConvertStrToVer(szVer, pwVer);
  143. if (pszVer)
  144. StrCpyN(pszVer, szVer, cch);
  145. fInstalled = TRUE;
  146. }
  147. }
  148. }
  149. RegCloseKey(hkey);
  150. }
  151. return fInstalled;
  152. }
  153. /*******************************************************************
  154. NAME: GetExePath
  155. ********************************************************************/
  156. BOOL GetExePath(IN LPCTSTR szExe,
  157. OUT TCHAR *szPath,
  158. IN DWORD cch,
  159. IN BOOL fDirOnly)
  160. {
  161. BOOL fRet = FALSE;
  162. HKEY hkey;
  163. DWORD dwType, cb;
  164. TCHAR sz[MAX_PATH], szT[MAX_PATH];
  165. // Validate params
  166. Assert(szExe != NULL);
  167. Assert(szPath != NULL);
  168. Assert(cch);
  169. wnsprintf(sz, ARRAYSIZE(sz), c_szPathFileFmt, c_szAppPaths, szExe);
  170. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, sz, 0, KEY_QUERY_VALUE, &hkey))
  171. {
  172. cb = sizeof(szT);
  173. if (ERROR_SUCCESS == RegQueryValueEx(hkey, fDirOnly ? c_szRegPath : NULL, 0, &dwType, (LPBYTE)szT, &cb) && cb)
  174. {
  175. if (REG_EXPAND_SZ == dwType)
  176. {
  177. cb = ExpandEnvironmentStrings(szT, szPath, cch);
  178. if (cb != 0 && cb <= cch)
  179. fRet = TRUE;
  180. }
  181. else
  182. {
  183. Assert(REG_SZ == dwType);
  184. StrCpyN(szPath, szT, cch);
  185. fRet = TRUE;
  186. }
  187. }
  188. RegCloseKey(hkey);
  189. }
  190. return(fRet);
  191. }
  192. /*******************************************************************
  193. NAME: GetFileVer
  194. ********************************************************************/
  195. HRESULT GetFileVer(IN LPCTSTR pszExePath,
  196. OUT LPTSTR pszVer,
  197. IN DWORD cch)
  198. {
  199. DWORD dwVerInfoSize, dwVerHnd;
  200. HRESULT hr = S_OK;
  201. LPSTR pszInfo = NULL;
  202. LPSTR pszVersion;
  203. LPWORD pwTrans;
  204. TCHAR szGet[MAX_PATH];
  205. UINT uLen;
  206. // Validate Parameters
  207. Assert(pszExePath);
  208. Assert(pszVer);
  209. Assert(cch);
  210. // Initialize out parameters
  211. pszVer[0] = TEXT('\0');
  212. // Allocate space for version info block
  213. if (0 == (dwVerInfoSize = GetFileVersionInfoSize(const_cast<LPTSTR> (pszExePath), &dwVerHnd)))
  214. {
  215. hr = E_FAIL;
  216. TraceResult(hr);
  217. goto exit;
  218. }
  219. IF_NULLEXIT(pszInfo = (LPTSTR)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, dwVerInfoSize));
  220. // Get Version info block
  221. IF_FALSEEXIT(GetFileVersionInfo(const_cast<LPTSTR> (pszExePath), dwVerHnd, dwVerInfoSize, pszInfo), E_FAIL);
  222. // Figure out language for version info
  223. IF_FALSEEXIT(VerQueryValue(pszInfo, "\\VarFileInfo\\Translation", (LPVOID *)&pwTrans, &uLen) && uLen >= (2 * sizeof(WORD)), E_FAIL);
  224. // Set up buffer with correct language and get version
  225. wnsprintf(szGet, ARRAYSIZE(szGet), "\\StringFileInfo\\%04X%04X\\FileVersion", pwTrans[0], pwTrans[1]);
  226. IF_FALSEEXIT(VerQueryValue(pszInfo, szGet, (LPVOID *)&pszVersion, &uLen) && uLen, E_FAIL);
  227. // Copy version out of version block, into out param
  228. Assert(pszVersion);
  229. StrCpyN(pszVer, pszVersion, cch);
  230. exit:
  231. if (pszInfo)
  232. GlobalFree((HGLOBAL)pszInfo);
  233. return hr;
  234. }
  235. /*******************************************************************
  236. NAME: GetExeVer
  237. ********************************************************************/
  238. HRESULT GetExeVer(IN LPCTSTR pszExeName,
  239. OUT WORD *pwVer, // OPTIONAL
  240. OUT LPTSTR pszVer, // OPTIONAL
  241. IN int cch) // OPTIONAL
  242. {
  243. HRESULT hr = S_OK;
  244. TCHAR szPath[MAX_PATH];
  245. TCHAR szVer[64];
  246. // Validate params
  247. Assert(pszExeName);
  248. // Initialize out params
  249. if (pszVer)
  250. {
  251. Assert(cch);
  252. pszVer[0] = 0;
  253. }
  254. if (pwVer)
  255. // Version is an array of 4 words
  256. ZeroMemory(pwVer, 4 * sizeof(*pwVer));
  257. // Find the exe
  258. IF_FALSEEXIT(GetExePath(pszExeName, szPath, ARRAYSIZE(szPath), FALSE), E_FAIL);
  259. // Get the string representation of the version
  260. IF_FAILEXIT(hr = GetFileVer(szPath, szVer, ARRAYSIZE(szVer)));
  261. // Fill in out params
  262. if (pwVer)
  263. ConvertStrToVer(szVer, pwVer);
  264. if (pszVer)
  265. StrCpyN(pszVer, szVer, cch);
  266. exit:
  267. return hr;
  268. }
  269. /*******************************************************************
  270. NAME: DetectPrevVer
  271. SYNOPSIS: Called when there is no ver info for current app
  272. ********************************************************************/
  273. SETUPVER DetectPrevVer(IN SETUPAPP saApp,
  274. OUT LPTSTR pszVer,
  275. IN int cch)
  276. {
  277. DWORD dwAttr;
  278. SETUPVER sv;
  279. TCHAR szVer[VERLEN] = {0};
  280. TCHAR szFile[MAX_PATH];
  281. TCHAR szFile2[MAX_PATH];
  282. UINT uLen, uLen2;
  283. WORD wVer[4];
  284. // Validate params
  285. Assert(pszVer);
  286. uLen = GetSystemDirectory(szFile, ARRAYSIZE(szFile));
  287. if ('\\' != *CharPrev(szFile, szFile + uLen))
  288. szFile[uLen++] = '\\';
  289. switch (saApp)
  290. {
  291. case APP_OE:
  292. StrCpyN(&szFile[uLen], c_szMAILNEWS, ARRAYSIZE(szFile) - uLen);
  293. // See what version we've told IE Setup, is installed
  294. // Or what version msimn.exe is (to cover the case in which the
  295. // ASetup info has been damaged - OE 5.01 80772)
  296. if (GetASetupVer(c_szOEGUID, wVer, szVer, ARRAYSIZE(szVer)) ||
  297. SUCCEEDED(GetExeVer(c_szOldMainExe, wVer, szVer, ARRAYSIZE(szVer))))
  298. sv = ConvertVerToEnum(wVer);
  299. else
  300. {
  301. // 1.0 or none
  302. // Does mailnews.dll exist?
  303. if(0xFFFFFFFF == GetFileAttributes(szFile))
  304. sv = VER_NONE;
  305. else
  306. sv = VER_1_0;
  307. }
  308. // If active setup, these will be rollably deleted
  309. FORCE_DEL(szFile);
  310. break;
  311. case APP_WAB:
  312. StrCpyN(&szFile[uLen], c_szWAB32, ARRAYSIZE(szFile) - uLen);
  313. uLen2 = GetWindowsDirectory(szFile2, ARRAYSIZE(szFile2));
  314. if ('\\' != *CharPrev(szFile2, szFile2 + uLen2))
  315. szFile2[uLen2++] = '\\';
  316. StrCpyN(&szFile2[uLen2], c_szWABEXE, ARRAYSIZE(szFile2) - uLen2);
  317. if (GetASetupVer(c_szWABGUID, wVer, szVer, ARRAYSIZE(szVer)))
  318. {
  319. // 5.0 or later
  320. if (5 == wVer[0])
  321. sv = VER_5_0;
  322. else
  323. sv = VER_MAX;
  324. }
  325. else if (GetASetupVer(c_szOEGUID, wVer, szVer, ARRAYSIZE(szVer)) ||
  326. SUCCEEDED(GetExeVer(c_szOldMainExe, wVer, szVer, ARRAYSIZE(szVer))))
  327. {
  328. // 4.0x or 5.0 Beta 1
  329. if (5 == wVer[0])
  330. sv = VER_5_0_B1;
  331. else if (4 == wVer[0])
  332. sv = VER_4_0;
  333. else
  334. sv = VER_MAX;
  335. }
  336. else
  337. {
  338. // 1.0, 1.1 or none
  339. // WAB32.dll around?
  340. if(0xFFFFFFFF == GetFileAttributes(szFile))
  341. sv = VER_NONE;
  342. else
  343. {
  344. // \Windows\Wab.exe around?
  345. if(0xFFFFFFFF == GetFileAttributes(szFile2))
  346. sv = VER_1_0;
  347. else
  348. sv = VER_1_1;
  349. }
  350. }
  351. // If active setup, these will be rollably deleted
  352. FORCE_DEL(szFile);
  353. FORCE_DEL(szFile2);
  354. break;
  355. default:
  356. sv = VER_NONE;
  357. }
  358. // Figure out the build number for this ver
  359. if (szVer[0])
  360. // Use real ver
  361. StrCpyN(pszVer, szVer, cch);
  362. else
  363. // Fake Ver
  364. StrCpyN(pszVer, c_szBlds[sv], cch);
  365. return sv;
  366. }
  367. /*******************************************************************
  368. NAME: LookForApp
  369. ********************************************************************/
  370. BOOL LookForApp(IN SETUPAPP saApp,
  371. OUT LPTSTR pszVer,
  372. IN int cch,
  373. OUT SETUPVER svInterimVer)
  374. {
  375. BOOL fReg = FALSE;
  376. DWORD cb;
  377. HKEY hkey;
  378. LPCTSTR pszVerInfo;
  379. SETUPVER svCurr = VER_MAX, svPrev = VER_MAX;
  380. TCHAR szCurrVer[VERLEN]={0};
  381. TCHAR szPrevVer[VERLEN]={0};
  382. LPTSTR psz = szCurrVer;
  383. WORD wVer[4];
  384. // Validate Params
  385. Assert(pszVer);
  386. Assert(cch);
  387. // Initialize out params
  388. svInterimVer = VER_NONE;
  389. *pszVer = TEXT('\0');
  390. switch (saApp)
  391. {
  392. case APP_OE:
  393. pszVerInfo = c_szRegVerInfo;
  394. break;
  395. case APP_WAB:
  396. pszVerInfo = c_szRegWABVerInfo;
  397. break;
  398. default:
  399. // Should never happen
  400. AssertFalseSz("Looking up an unknown app?");
  401. goto exit;
  402. }
  403. // Always try to use the version info
  404. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszVerInfo, 0, KEY_QUERY_VALUE, &hkey))
  405. {
  406. cb = sizeof(szPrevVer);
  407. RegQueryValueEx(hkey, c_szRegPrevVer, NULL, NULL, (LPBYTE)szPrevVer, &cb);
  408. // Change to a bld # if needed
  409. if (!TranslateVers(&svPrev, szPrevVer, ARRAYSIZE(szPrevVer)))
  410. {
  411. // Convert bld to enum
  412. ConvertStrToVer(szPrevVer, wVer);
  413. svPrev = ConvertVerToEnum(wVer);
  414. }
  415. // If version info shows that a ver info aware version was uninstalled, throw out the info
  416. // and redetect
  417. if (VER_NONE == svPrev)
  418. // Sniff the machine for current version
  419. svCurr = DetectPrevVer(saApp, szCurrVer, ARRAYSIZE(szCurrVer));
  420. else
  421. {
  422. // There was previous version reg goo - and it's legit
  423. fReg = TRUE;
  424. cb = sizeof(szCurrVer);
  425. RegQueryValueEx(hkey, c_szRegCurrVer, NULL, NULL, (LPBYTE)szCurrVer, &cb);
  426. // Change to a bld # if needed
  427. if (!TranslateVers(&svCurr, szCurrVer, ARRAYSIZE(szCurrVer)))
  428. {
  429. // Convert bld to enum
  430. ConvertStrToVer(szCurrVer, wVer);
  431. svCurr = ConvertVerToEnum(wVer);
  432. }
  433. }
  434. RegCloseKey(hkey);
  435. }
  436. else
  437. {
  438. // Sniff the machine for current version
  439. svCurr = DetectPrevVer(saApp, szCurrVer, ARRAYSIZE(szCurrVer));
  440. }
  441. // Should we change the previous version entry?
  442. if (VER_5_0 != svCurr)
  443. {
  444. // Know this is B1 OE if we translated
  445. // Know this is B1 WAB if we detected it
  446. if (VER_5_0_B1 == svCurr)
  447. {
  448. svInterimVer = svCurr;
  449. // Did we read a previous value?
  450. if (fReg)
  451. // As there were reg entries, just translate the previous entry
  452. psz = szPrevVer;
  453. else
  454. {
  455. // We don't have a bld number and yet we are B1, better be the WAB
  456. Assert(APP_WAB == saApp);
  457. // Peek at OE's ver info
  458. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegVerInfo, 0, KEY_QUERY_VALUE, &hkey))
  459. {
  460. cb = sizeof(szPrevVer);
  461. // Read a build or a string
  462. RegQueryValueExA(hkey, c_szRegPrevVer, NULL, NULL, (LPBYTE)szPrevVer, &cb);
  463. // If it's a string, convert it to a build
  464. TranslateVers(&svPrev, szPrevVer, ARRAYSIZE(szPrevVer));
  465. // We'll use the build (translated or direct)
  466. psz = szPrevVer;
  467. RegCloseKey(hkey);
  468. }
  469. }
  470. }
  471. // Fill in out param
  472. StrCpyN(pszVer, psz, cch);
  473. }
  474. exit:
  475. return (VER_NONE != svCurr);
  476. }