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.

1840 lines
55 KiB

  1. /******************************************************************************\
  2. *
  3. * CDCACHE.EXE
  4. *
  5. * Synopsis:
  6. * An AutoRun EXE to enable easy addition of CD-ROM content
  7. * into the Internet Explorer (WININET) Persistent URL Cache.
  8. *
  9. * Usage:
  10. * Place an AUTORUN.INF at the root of the CD-ROM which has content
  11. * that you want to register with the WININET Persistent URL Cache.
  12. * Contents of AUTORUN.INF:
  13. *
  14. * [autorun]
  15. * open=cdcache.exe
  16. * icon=cdcache.exe, 1
  17. *
  18. * Additionally create a CDCACHE.INF at the root of the CD-ROM.
  19. * Typical contents:
  20. *
  21. * [Add.CacheContainer]
  22. * <Friendly Unique Vendor Name>=<INF Section Name>
  23. *
  24. * [INF Section Name]
  25. * CachePrefix=<string>
  26. * CacheRoot=<relative path on CD-ROM of data>
  27. * KBCacheLimit=<numerical amount in KB>
  28. * AutoDelete=Yes|No (default)
  29. * IncludeSubDirs=Yes (default) |No
  30. * NoDesktopInit=Yes|No (default)
  31. *
  32. *
  33. * CMD Line Options:
  34. * /Silent Install Cache Container without showing UI
  35. * /Remove Uninstall the cache container
  36. * /Uninstall same as /Remove
  37. *
  38. * History
  39. * 23June97 robgil created
  40. * 06Aug97 robgil add IE4 wininet.dll checks
  41. * 26Aug97 robgil manual register if no IE4
  42. *
  43. * Copyright (C) 1994-1997 Microsoft Corporation.
  44. * All rights reserved.
  45. *
  46. \******************************************************************************/
  47. #include "stdhdr.h"
  48. /////////////////////////////////////////////////////////////////////////
  49. // Defines and Type Declarations
  50. #define STRING_BUFFER_SIZE 256
  51. #define CACHE_ACTION_INSTALL 0
  52. #define CACHE_ACTION_REMOVE 1
  53. #define CACHE_ACTION_FILL_LB 2
  54. #define CACHE_ACTION_MAKE_REG_ENTRIES 3
  55. typedef BOOL (CALLBACK* LPFNCREATEURLCACHECONTAINER)(LPCSTR,LPCSTR,LPCSTR,DWORD,DWORD,DWORD,LPVOID,LPDWORD);
  56. typedef BOOL (CALLBACK* LPFNDELETEURLCACHECONTAINER)(LPCSTR,DWORD);
  57. typedef HANDLE (CALLBACK* LPFNFINDFIRSTURLCACHECONTAINER)(LPDWORD,LPINTERNET_CACHE_CONTAINER_INFO,LPDWORD,DWORD);
  58. typedef BOOL (CALLBACK* LPFNFINDNEXTURLCACHECONTAINER)(HANDLE,LPINTERNET_CACHE_CONTAINER_INFO,LPDWORD);
  59. typedef BOOL (CALLBACK* LPFNFINDCLOSEURLCACHE)(HANDLE);
  60. typedef BOOL (CALLBACK* LPFNGETURLCACHECONFIGINFO)(LPINTERNET_CACHE_CONFIG_INFO,LPDWORD,DWORD);
  61. /////////////////////////////////////////////////////////////////////////
  62. // Global Variables:
  63. HINSTANCE g_hInst; // current instance
  64. BOOL g_fRunSilent = FALSE; // True = show no UI
  65. BOOL g_fRemove = FALSE; // True = remove the cache containers in INF
  66. //BOOL g_fNoIE4Msg = FALSE; // True = do not show UI saying IE4 WININET is required
  67. BOOL g_fNoIE4 = FALSE; // IE4 WININET is not available
  68. TCHAR gszIniValTrue[] = INI_TRUE ;
  69. TCHAR gszIniValFalse[] = INI_FALSE ;
  70. TCHAR gszIniValOn[] = INI_ON ;
  71. TCHAR gszIniValOff[] = INI_OFF ;
  72. TCHAR gszIniValYes[] = INI_YES ;
  73. TCHAR gszIniValNo[] = INI_NO ;
  74. LPFNCREATEURLCACHECONTAINER lpfnCreateUrlCacheContainer = NULL;
  75. LPFNDELETEURLCACHECONTAINER lpfnDeleteUrlCacheContainer = NULL;
  76. LPFNFINDFIRSTURLCACHECONTAINER lpfnFindFirstUrlCacheContainer = NULL;
  77. LPFNFINDNEXTURLCACHECONTAINER lpfnFindNextUrlCacheContainer = NULL;
  78. LPFNFINDCLOSEURLCACHE lpfnFindCloseUrlCache = NULL;
  79. LPFNGETURLCACHECONFIGINFO lpfnGetUrlCacheConfigInfo = NULL;
  80. /////////////////////////////////////////////////////////////////////////
  81. // Foward declarations of functions included in this code module:
  82. INT_PTR CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
  83. BOOL CenterWindow (HWND, HWND);
  84. int OnInitDialog(HWND hDlg);
  85. BOOL LoadWininet(void);
  86. BOOL WininetLoaded(void);
  87. BOOL CacheContainer(DWORD *dwTotal, DWORD *dwInstalled, DWORD dwAction, HWND hListBox);
  88. HRESULT ExpandEntry(
  89. LPSTR szSrc,
  90. LPSTR szBuf,
  91. DWORD cbBuffer,
  92. const char * szVars[],
  93. const char * szValues[]);
  94. HRESULT ExpandVar(
  95. LPSTR& pchSrc, // passed by ref!
  96. LPSTR& pchOut, // passed by ref!
  97. DWORD& cbLen, // passed by ref!
  98. DWORD cbBuffer, // size of out buffer
  99. const char * szVars[], // array of variable names eg. %EXE_ROOT%
  100. const char * szValues[]);// corresponding values to expand of vars
  101. LPSTR GetINFDir(LPSTR lpBuffer, int nBuffSize);
  102. LPSTR GetINFDrive(LPSTR lpBuffer, int nBuffSize);
  103. WORD GetProfileBooleanWord(LPCTSTR szIniSection, LPCTSTR szKeyName, LPCTSTR szIniFile);
  104. DWORD CreateAdditionalEntries(LPCSTR lpszUniqueVendorName, LPCSTR lpszVolumeTitle, LPCSTR lpszVolumeLabel, LPCSTR lpszPrefixMap);
  105. DWORD GetPrefixMapEntry(LPCSTR lpszUniqueVendorName, LPSTR lpszPrefixMap, DWORD cbPrefixMap);
  106. BOOL UrlCacheContainerExists(LPCSTR lpszUniqueVendorName, LPCSTR lpszCachePrefix, LPCSTR lpszPrefixMap);
  107. // WININET CreateUrlCacheContainer WRAPPER
  108. // Wraps up the hacks in one spot - see f() header for details
  109. BOOL _CreateUrlCacheContainer(
  110. IN LPCSTR lpszUniqueVendorName,
  111. IN LPCSTR lpszCachePrefix,
  112. IN LPCSTR lpszPrefixMap, // New - part of WRAPPER
  113. IN LPCSTR lpszVolumeTitle, // New - part of WRAPPER
  114. IN LPCSTR lpszVolumeLabel, // New - part of Wrapper.
  115. IN DWORD KBCacheLimit,
  116. IN DWORD dwContainerType,
  117. IN DWORD dwOptions
  118. );
  119. /************************************************************************\
  120. * FUNCTION: WinMain
  121. \************************************************************************/
  122. int APIENTRY WinMain(HINSTANCE g_hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  123. {
  124. LPSTR lpszCmd = NULL;
  125. DWORD dwTotal = 0;
  126. DWORD dwInstalled = 0;
  127. g_hInst = g_hInstance;
  128. // Parse lpCmdLine looking for options we understand
  129. TCHAR szTokens[] = _T("-/ ");
  130. LPTSTR lpszToken = _tcstok(lpCmdLine, szTokens);
  131. while (lpszToken != NULL)
  132. {
  133. if (_tcsicmp(lpszToken, _T("Silent"))==0)
  134. g_fRunSilent = TRUE;
  135. else if (_tcsicmp(lpszToken, _T("Remove"))==0)
  136. g_fRemove = TRUE;
  137. else if (_tcsicmp(lpszToken, _T("Uninstall"))==0)
  138. g_fRemove = TRUE;
  139. // else if (_tcsicmp(lpszToken, _T("NoIE4Msg"))==0)
  140. // g_fNoIE4Msg = TRUE;
  141. lpszToken = _tcstok(NULL, szTokens);
  142. }
  143. // Check for IE4 or higher WININET.DLL version
  144. // and dynamically load it and init global function pointers
  145. // to WININET f() used in this application
  146. // This will avoid Undefined Dynalink errors when run on a
  147. // system without IE4
  148. if (!LoadWininet())
  149. {
  150. g_fNoIE4 = TRUE;
  151. // Put up message about requiring IE4 WININET
  152. /* Since we workaround not having IE4 - no need for message
  153. if (!g_fNoIE4Msg)
  154. {
  155. char szString[128]; // Keep string 70% larger for localization
  156. char szCaption[128]; // Keep string 70% larger for localization
  157. LoadString (g_hInst, ID_APPNAME, szCaption, sizeof(szCaption));
  158. LoadString (g_hInst, IDM_NEEDIE4WININET, szString, sizeof(szString));
  159. MessageBox(NULL, szString, szCaption, MB_OK);
  160. }
  161. */
  162. // Can't call WININET
  163. // Need to make registry entries to install cache containers
  164. //
  165. if (!CacheContainer(&dwTotal, &dwInstalled, CACHE_ACTION_FILL_LB, NULL))
  166. {
  167. if (g_fRunSilent)
  168. {
  169. // Create cache entries in silent mode.
  170. CacheContainer(&dwTotal, &dwInstalled, CACHE_ACTION_MAKE_REG_ENTRIES, NULL);
  171. }
  172. else
  173. {
  174. // Otherwise run app.
  175. DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_MAINAPP), NULL, DlgProc);
  176. }
  177. return(FALSE);
  178. }
  179. return 0; // Quit and go home
  180. }
  181. if (!g_fRunSilent)
  182. {
  183. // Only want to put up UI if any of the containers are NOT installed
  184. // (this includes those containers that are installed but the
  185. // PrefixMap entry is incorrect - i.e. wrong drive)
  186. if (!CacheContainer(&dwTotal, &dwInstalled, CACHE_ACTION_FILL_LB, NULL))
  187. {
  188. DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_MAINAPP), NULL, DlgProc);
  189. return(FALSE);
  190. }
  191. else
  192. {
  193. // All the CacheContainers are already installed or there is no INF
  194. // so check if we want to uninstall
  195. // OnInitDialog checks the g_fRemove flags and POST's a msg
  196. // to dialog to initiate the Uninstall steps
  197. if (g_fRemove)
  198. DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_MAINAPP), NULL, DlgProc);
  199. }
  200. }
  201. else
  202. {
  203. DWORD dwAction = CACHE_ACTION_INSTALL; // default action is INSTALL
  204. // We're running silent and deep - all quiet on board
  205. // we don't need no stinkin window
  206. if (g_fRemove)
  207. dwAction = CACHE_ACTION_REMOVE;
  208. if (!CacheContainer(&dwTotal, &dwInstalled, dwAction, NULL))
  209. {
  210. // BUGBUG: Since we're running silent what
  211. // should we do on failure?
  212. }
  213. return 0;
  214. }
  215. return 0;
  216. }
  217. /************************************************************************\
  218. * FUNCTION: DlgProc
  219. \************************************************************************/
  220. INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  221. {
  222. int wmId, wmEvent;
  223. switch (message)
  224. {
  225. case WM_INITDIALOG:
  226. return OnInitDialog(hDlg);
  227. case WM_COMMAND:
  228. wmId = LOWORD(wParam); // Remember, these are...
  229. wmEvent = HIWORD(wParam); // ...different for Win32!
  230. switch (wmId)
  231. {
  232. case IDM_INSTALL:
  233. {
  234. DWORD dwError = 0;
  235. DWORD dwTotal = 0;
  236. DWORD dwInstalled = 0;
  237. DWORD dwAction = 0;
  238. if (g_fNoIE4)
  239. dwAction = CACHE_ACTION_MAKE_REG_ENTRIES;
  240. else
  241. dwAction = CACHE_ACTION_INSTALL;
  242. if (!CacheContainer(&dwTotal, &dwInstalled, dwAction, NULL))
  243. {
  244. dwError = GetLastError();
  245. }
  246. if (dwInstalled > 0)
  247. {
  248. char szString[128]; // Keep string 70% larger for localization
  249. char szBuffer[256];
  250. // Successfully installed a cache container
  251. // though not necessarily all of them.
  252. LoadString (g_hInst, IDM_SUCCESS, szString, sizeof(szString));
  253. wsprintf(szBuffer, szString, dwInstalled, dwTotal);
  254. LoadString (g_hInst, ID_APPNAME, szString, sizeof(szString));
  255. MessageBox(hDlg, szBuffer, szString, MB_OK);
  256. // We're done close this app
  257. PostMessage (hDlg, WM_CLOSE, 0, 0);
  258. }
  259. else
  260. {
  261. char szString[128]; // Keep string 70% larger for localization
  262. char szBuffer[256];
  263. // Unable to install any of the cache containers successfully
  264. LoadString (g_hInst, IDM_FAILED, szString, sizeof(szString));
  265. wsprintf(szBuffer, szString, dwTotal);
  266. LoadString (g_hInst, ID_APPNAME, szString, sizeof(szString));
  267. MessageBox(hDlg, szBuffer, szString, MB_OK);
  268. }
  269. break;
  270. }
  271. case IDM_UNINSTALL:
  272. {
  273. DWORD dwError = 0;
  274. DWORD dwTotal = 0;
  275. DWORD dwRemoved = 0;
  276. if (g_fNoIE4)
  277. {
  278. char szString[128]; // Keep string 70% larger for localization
  279. char szBuffer[256];
  280. // Uninstall of cache containers requires IE4
  281. LoadString (g_hInst, IDM_ERR_IE4REQFORUNINSTALL, szString, sizeof(szString));
  282. wsprintf(szBuffer, szString, dwRemoved, dwTotal);
  283. LoadString (g_hInst, ID_APPNAME, szString, sizeof(szString));
  284. MessageBox(hDlg, szBuffer, szString, MB_OK);
  285. }
  286. else
  287. {
  288. if (!CacheContainer(&dwTotal, &dwRemoved, CACHE_ACTION_REMOVE, NULL))
  289. {
  290. dwError = GetLastError();
  291. }
  292. if (dwRemoved > 0)
  293. {
  294. char szString[128]; // Keep string 70% larger for localization
  295. char szBuffer[256];
  296. // Successfully UnInstalled a cache container
  297. // though not necessarily all of them.
  298. LoadString (g_hInst, IDM_SUCCESS_REMOVE, szString, sizeof(szString));
  299. wsprintf(szBuffer, szString, dwRemoved, dwTotal);
  300. LoadString (g_hInst, ID_APPNAME, szString, sizeof(szString));
  301. MessageBox(hDlg, szBuffer, szString, MB_OK);
  302. }
  303. else
  304. {
  305. char szString[128]; // Keep string 70% larger for localization
  306. char szBuffer[256];
  307. // Unable to install any of the cache containers successfully
  308. LoadString (g_hInst, IDM_FAILED_REMOVE, szString, sizeof(szString));
  309. wsprintf(szBuffer, szString, dwTotal);
  310. LoadString (g_hInst, ID_APPNAME, szString, sizeof(szString));
  311. MessageBox(hDlg, szBuffer, szString, MB_OK);
  312. }
  313. }
  314. if (g_fRemove)
  315. {
  316. // We're done close this app
  317. PostMessage (hDlg, WM_CLOSE, 0, 0);
  318. }
  319. break;
  320. }
  321. case IDCANCEL:
  322. EndDialog(hDlg, TRUE);
  323. break;
  324. default:
  325. return (FALSE);
  326. }
  327. break;
  328. default:
  329. return (FALSE);
  330. }
  331. return (TRUE);
  332. }
  333. /************************************************************************\
  334. * FUNCTION: CenterWindow
  335. \************************************************************************/
  336. // This is a 'utility' function I find usefull. It will center one
  337. // window over another. It also makes sure that the placement is within
  338. // the 'working area', meaning that it is both within the display limits
  339. // of the screen, -and- not obscured by the tray or other frameing
  340. // elements of the desktop.
  341. BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
  342. {
  343. RECT rChild, rParent, rWorkArea = {0,0,0,0};
  344. int wChild, hChild, wParent, hParent;
  345. int wScreen, hScreen, xScreen, yScreen, xNew, yNew;
  346. BOOL bResult;
  347. // Get the Height and Width of the child window
  348. GetWindowRect (hwndChild, &rChild);
  349. wChild = rChild.right - rChild.left;
  350. hChild = rChild.bottom - rChild.top;
  351. // Get the Height and Width of the parent window
  352. GetWindowRect (hwndParent, &rParent);
  353. wParent = rParent.right - rParent.left;
  354. hParent = rParent.bottom - rParent.top;
  355. // Get the limits of the 'workarea'
  356. #if !defined(SPI_GETWORKAREA)
  357. #define SPI_GETWORKAREA 48
  358. #endif
  359. bResult = SystemParametersInfo(
  360. SPI_GETWORKAREA, // system parameter to query or set
  361. sizeof(RECT), // depends on action to be taken
  362. &rWorkArea, // depends on action to be taken
  363. 0);
  364. wScreen = rWorkArea.right - rWorkArea.left;
  365. hScreen = rWorkArea.bottom - rWorkArea.top;
  366. xScreen = rWorkArea.left;
  367. yScreen = rWorkArea.top;
  368. // On Windows NT, the above metrics aren't valid (yet), so they all return
  369. // '0'. Lets deal with that situation properly:
  370. if (wScreen==0 && hScreen==0) {
  371. wScreen = GetSystemMetrics(SM_CXSCREEN);
  372. hScreen = GetSystemMetrics(SM_CYSCREEN);
  373. xScreen = 0; // These values should already be '0', but just in case
  374. yScreen = 0;
  375. }
  376. // Calculate new X position, then adjust for screen
  377. xNew = rParent.left + ((wParent - wChild) /2);
  378. if (xNew < xScreen) {
  379. xNew = xScreen;
  380. } else if ((xNew+wChild) > wScreen) {
  381. xNew = (xScreen + wScreen) - wChild;
  382. }
  383. // Calculate new Y position, then adjust for screen
  384. yNew = rParent.top + ((hParent - hChild) /2);
  385. if (yNew < yScreen) {
  386. yNew = yScreen;
  387. } else if ((yNew+hChild) > hScreen) {
  388. yNew = (yScreen + hScreen) - hChild;
  389. }
  390. // Set it, and return
  391. return SetWindowPos (hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
  392. }
  393. int OnInitDialog(HWND hDlg)
  394. {
  395. HWND hListBox;
  396. DWORD dwRemoved = 0;
  397. DWORD dwTotal = 0;
  398. CenterWindow (hDlg, GetDesktopWindow ());
  399. hListBox = GetDlgItem(hDlg, IDC_LIST);
  400. // Populate list box with Cache Container list
  401. CacheContainer(&dwTotal, &dwRemoved, CACHE_ACTION_FILL_LB, hListBox);
  402. // #57353 - after adding don't show UI if already installed
  403. // we forgot to account for /uninstall on cmd line
  404. if (g_fRemove)
  405. PostMessage(hDlg, WM_COMMAND, IDM_UNINSTALL, 0L);
  406. return FALSE;
  407. }
  408. /************************************************************************\
  409. * FUNCTION: LoadWininet()
  410. *
  411. * If IE4 or greater version of WININET then load it up and establish
  412. * function pointers to use in rest of application.
  413. *
  414. * returns BOOL
  415. * TRUE - Sufficient version of WININET.DLL is available
  416. * FALSE - WININET.DLL is not new enough for our purposes
  417. *
  418. \************************************************************************/
  419. BOOL LoadWininet()
  420. {
  421. HINSTANCE hDll;
  422. hDll = LoadLibrary("WININET.DLL");
  423. if (hDll != NULL)
  424. {
  425. lpfnCreateUrlCacheContainer = (LPFNCREATEURLCACHECONTAINER)GetProcAddress(hDll, "CreateUrlCacheContainerA");
  426. lpfnDeleteUrlCacheContainer = (LPFNDELETEURLCACHECONTAINER)GetProcAddress(hDll, "DeleteUrlCacheContainerA");
  427. lpfnFindFirstUrlCacheContainer = (LPFNFINDFIRSTURLCACHECONTAINER)GetProcAddress(hDll, "FindFirstUrlCacheContainerA");
  428. lpfnFindNextUrlCacheContainer = (LPFNFINDNEXTURLCACHECONTAINER)GetProcAddress(hDll, "FindNextUrlCacheContainerA");
  429. lpfnFindCloseUrlCache = (LPFNFINDCLOSEURLCACHE)GetProcAddress(hDll, "FindCloseUrlCache");
  430. lpfnGetUrlCacheConfigInfo = (LPFNGETURLCACHECONFIGINFO)GetProcAddress(hDll, "GetUrlCacheConfigInfoA");
  431. if ( (!lpfnCreateUrlCacheContainer) ||
  432. (!lpfnDeleteUrlCacheContainer) ||
  433. (!lpfnFindFirstUrlCacheContainer) ||
  434. (!lpfnFindNextUrlCacheContainer) ||
  435. (!lpfnFindCloseUrlCache) ||
  436. (!lpfnGetUrlCacheConfigInfo) )
  437. {
  438. lpfnCreateUrlCacheContainer = NULL;
  439. lpfnDeleteUrlCacheContainer = NULL;
  440. lpfnFindFirstUrlCacheContainer = NULL;
  441. lpfnFindNextUrlCacheContainer = NULL;
  442. lpfnFindCloseUrlCache = NULL;
  443. lpfnGetUrlCacheConfigInfo = NULL;
  444. FreeLibrary(hDll);
  445. return FALSE;
  446. }
  447. }
  448. else
  449. return FALSE;
  450. return TRUE;
  451. }
  452. /************************************************************************\
  453. * FUNCTION: WininetLoaded()
  454. *
  455. * returns BOOL
  456. * TRUE - Sufficient version of WININET.DLL is available
  457. * FALSE - WININET.DLL is not new enough for our purposes
  458. *
  459. \************************************************************************/
  460. BOOL WininetLoaded()
  461. {
  462. if (lpfnCreateUrlCacheContainer)
  463. return TRUE;
  464. return FALSE;
  465. }
  466. /************************************************************************\
  467. * FUNCTION: UrlCacheContainerExists()
  468. *
  469. *
  470. * returns BOOL
  471. * TRUE - This cache container is already installed and PrefixMap
  472. * location is correct
  473. * FALSE - Cache container is not installed or it's PrefixMap
  474. * location is different
  475. *
  476. \************************************************************************/
  477. BOOL UrlCacheContainerExists(LPCSTR lpszUniqueVendorName, LPCSTR lpszCachePrefix, LPCSTR lpszPrefixMap)
  478. {
  479. BYTE bBuf[4096];
  480. LPINTERNET_CACHE_CONTAINER_INFO lpCCI = (LPINTERNET_CACHE_CONTAINER_INFO) bBuf;
  481. DWORD cbCEI = sizeof(bBuf);
  482. DWORD dwModified = 0;
  483. HANDLE hEnum = NULL;
  484. BOOL bFound = FALSE;
  485. BOOL bReturn = FALSE;
  486. if (!WininetLoaded())
  487. return FALSE;
  488. // Look for our cache container, then determine if it already exists
  489. // also need to make sure PrefixMap entry is correct
  490. // for situation when CD is placed into a different drive
  491. // after it's already been installed
  492. hEnum = lpfnFindFirstUrlCacheContainer(&dwModified, lpCCI, &cbCEI, 0);
  493. if (0 == lstrcmpi(lpszUniqueVendorName, lpCCI->lpszName))
  494. bFound = TRUE;
  495. else
  496. {
  497. while (hEnum && lpfnFindNextUrlCacheContainer(hEnum, lpCCI, &cbCEI))
  498. {
  499. if (0 == lstrcmpi(lpszUniqueVendorName, lpCCI->lpszName))
  500. {
  501. bFound = TRUE;
  502. break;
  503. }
  504. }
  505. }
  506. if (bFound)
  507. {
  508. // Now check if URL CachePrefix pattern is the same
  509. if (0 == lstrcmpi(lpszCachePrefix, lpCCI->lpszCachePrefix))
  510. {
  511. char lpBuffer[256];
  512. DWORD cbBuffer = sizeof(lpBuffer);
  513. // Now check if PrefixMap entry is OK
  514. GetPrefixMapEntry(lpszUniqueVendorName, lpBuffer, cbBuffer);
  515. if (0 == lstrcmpi(lpBuffer, lpszPrefixMap))
  516. bReturn = TRUE;
  517. else
  518. bReturn = FALSE;
  519. // If both CachePrefix and PrefixMap match
  520. // then we consider this entry to already exist
  521. // and is correctly installed.
  522. }
  523. }
  524. if (hEnum)
  525. lpfnFindCloseUrlCache(hEnum);
  526. return bReturn;
  527. }
  528. /************************************************************************\
  529. * FUNCTION: _CreateUrlCacheContainer()
  530. *
  531. * Wrapper around WININET CreateUrlCacheContainer()
  532. *
  533. * Parameters:
  534. *
  535. * REMOVED
  536. * lpszUserLocalCachePath
  537. * Don't need to pass it in since can figure it out
  538. * using GetUrlCacheConfigInfo()
  539. *
  540. * ADDED
  541. * lpszPrefixMap Param added to wrapper, is missing from WININET f()
  542. * Specifies the location root path of the data
  543. * provided by the cache container.
  544. *
  545. * Workaround #1 - Pre-poplulate registry with PrefixMap
  546. * -----------------------------------------------------
  547. * In order to work properly must pre-populate registry
  548. * with the PrefixMap entry. Otherwise WININET CreateUrlCacheContainer()
  549. * will not install the cache container.
  550. *
  551. * STEP #1:
  552. * ========
  553. * Must setup registry entry in
  554. * HKCU\Software\Microsoft\Windows\CurrentVersion\
  555. * Internet Settings\Cache\Extensible Cache
  556. *
  557. * For PrefixMap
  558. * Key = <Unique Vendor Name>
  559. * PrefixMap = <string>
  560. *
  561. *
  562. * Other Entries include:
  563. * CacheLimit = <DWORD>
  564. * CacheOptions = <DWORD>
  565. * CachePath = <string>
  566. * CachePrefix = <string>
  567. * These should be put there by the call to CreateUrlCacheContainer()
  568. *
  569. * STEP #2
  570. * =======
  571. * Call CreateUrlCacheContainer()
  572. *
  573. * Locates all the 'workarounds' to one function.
  574. \************************************************************************/
  575. BOOL _CreateUrlCacheContainer(
  576. IN LPCSTR lpszUniqueVendorName,
  577. IN LPCSTR lpszCachePrefix,
  578. IN LPCSTR lpszPrefixMap, // New - part of WRAPPER
  579. IN LPCSTR lpszVolumeTitle, // New - part of WRAPPER
  580. IN LPCSTR lpszVolumeLabel, // New - part of WRAPPER
  581. IN DWORD KBCacheLimit,
  582. IN DWORD dwContainerType, // Not used by WININET currently
  583. IN DWORD dwOptions
  584. )
  585. {
  586. // Enough size to get our info first time without having to realloc
  587. BYTE bBuf[4096];
  588. LPINTERNET_CACHE_CONFIG_INFO lpCCI = (LPINTERNET_CACHE_CONFIG_INFO) bBuf;
  589. DWORD cbCEI = sizeof(bBuf);
  590. DWORD dwError = 0;
  591. char szCachePath[MAX_PATH];
  592. DWORD dwResult = ERROR_SUCCESS;
  593. if (!WininetLoaded())
  594. return FALSE;
  595. // Figure out local user cache location directory
  596. if (!lpfnGetUrlCacheConfigInfo(lpCCI, &cbCEI, CACHE_CONFIG_CONTENT_PATHS_FC))
  597. {
  598. // Look for ERROR_INSUFFICIENT_BUFFER and allocate enough
  599. if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
  600. {
  601. // BUGBUG: TODO: Handle insufficient buffer case
  602. // Try again using required size returned in cbCEI
  603. //lpCCI = new INTERNET_CACHE_CONFIG_INFO[cbCEI];
  604. }
  605. else
  606. dwError = GetLastError();
  607. }
  608. else
  609. {
  610. if (lpCCI->dwNumCachePaths > 0)
  611. lstrcpy(szCachePath, lpCCI->CachePaths[0].CachePath);
  612. }
  613. // Add Cache Container Unique Vendor Name to CachePath
  614. // All container content will be stored in this location
  615. if(lstrlen(szCachePath) + lstrlen(lpszUniqueVendorName) >= sizeof(szCachePath) / sizeof(szCachePath[0]))
  616. {
  617. return FALSE;
  618. }
  619. lstrcat(szCachePath, lpszUniqueVendorName);
  620. // Manually put PrefixMap into Registry
  621. // HKCU\Software\Microsoft\Windows\CurrentVersion\
  622. // Internet Settings\Cache\Extensible Cache
  623. CreateAdditionalEntries(lpszUniqueVendorName, lpszVolumeTitle, lpszVolumeLabel, lpszPrefixMap);
  624. // BUGBUG: Currently CreateUrlCacheContainer() fails if the entry
  625. // already exists. The returned GetLastError() is ERROR_INVALID_PARAM
  626. // Need to workaround this for now by enumerating the existing
  627. // cache containers and if found remove it and then re-add it.
  628. if (!lpfnCreateUrlCacheContainer(lpszUniqueVendorName, lpszCachePrefix,
  629. szCachePath, KBCacheLimit, dwContainerType,
  630. dwOptions, NULL, 0))
  631. {
  632. BYTE bBuf[4096];
  633. LPINTERNET_CACHE_CONTAINER_INFO lpCCI = (LPINTERNET_CACHE_CONTAINER_INFO) bBuf;
  634. DWORD cbCEI = sizeof(bBuf);
  635. DWORD dwModified = 0;
  636. HANDLE hEnum = NULL;
  637. int nCount = 0;
  638. // Assume we failed because cache container already exists
  639. // Look for our cache container, delete it, and re-create it
  640. hEnum = lpfnFindFirstUrlCacheContainer(&dwModified, lpCCI, &cbCEI, 0);
  641. if (0 == lstrcmpi(lpszUniqueVendorName, lpCCI->lpszName))
  642. {
  643. // BUGBUG: Need to specify any options?
  644. if (!lpfnDeleteUrlCacheContainer(lpszUniqueVendorName, 0))
  645. {
  646. dwResult = GetLastError();
  647. }
  648. else
  649. {
  650. CreateAdditionalEntries(lpszUniqueVendorName, lpszVolumeTitle, lpszVolumeLabel, lpszPrefixMap);
  651. if (!lpfnCreateUrlCacheContainer(lpszUniqueVendorName, lpszCachePrefix,
  652. szCachePath, KBCacheLimit, dwContainerType,
  653. dwOptions, NULL, 0))
  654. {
  655. dwResult = GetLastError();
  656. }
  657. }
  658. }
  659. else
  660. {
  661. while (hEnum && lpfnFindNextUrlCacheContainer(hEnum, lpCCI, &cbCEI))
  662. {
  663. if (0 == lstrcmpi(lpszUniqueVendorName, lpCCI->lpszName))
  664. {
  665. if (!lpfnDeleteUrlCacheContainer(lpszUniqueVendorName, 0))
  666. {
  667. dwResult = GetLastError();
  668. }
  669. else
  670. {
  671. CreateAdditionalEntries(lpszUniqueVendorName, lpszVolumeTitle, lpszVolumeLabel, lpszPrefixMap);
  672. if (!lpfnCreateUrlCacheContainer(lpszUniqueVendorName, lpszCachePrefix,
  673. szCachePath, KBCacheLimit, dwContainerType,
  674. dwOptions, NULL, 0))
  675. {
  676. dwResult = GetLastError();
  677. }
  678. break;
  679. }
  680. }
  681. nCount++;
  682. }
  683. }
  684. if (hEnum)
  685. lpfnFindCloseUrlCache(hEnum);
  686. }
  687. if (dwResult != ERROR_SUCCESS)
  688. return (FALSE);
  689. else
  690. return (TRUE);
  691. // return lpfnCreateUrlCacheContainer(lpszUniqueVendorName, lpszCachePrefix,
  692. // szCachePath, KBCacheLimit, dwContainerType,
  693. // dwOptions, NULL, 0);
  694. }
  695. /************************************************************************\
  696. * FUNCTION: CreateAdditionalEntries()
  697. *
  698. * Add the PrefixMap registry entry to the correct location in the
  699. * registry. A requirement to workaround this param missing from
  700. * the CreateUrlCacheContainer() WININET API.
  701. *
  702. \************************************************************************/
  703. DWORD CreateAdditionalEntries(LPCSTR lpszUniqueVendorName, LPCSTR lpszVolumeTitle,
  704. LPCSTR lpszVolumeLabel, LPCSTR lpszPrefixMap)
  705. {
  706. const static char *szKeyPrefixMap = "PrefixMap";
  707. const static char *szKeyVolumeLabel = "VolumeLabel";
  708. const static char *szKeyVolumeTitle = "VolumeTitle";
  709. const static char *szExtCacheRoot = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Extensible Cache";
  710. HKEY hKeyRoot = HKEY_CURRENT_USER; // default to current user
  711. HKEY hKeyCacheExt = 0;
  712. HKEY hKeyVendor = 0;
  713. DWORD dwDisposition = 0;
  714. DWORD dwResult = ERROR_SUCCESS;
  715. CHAR szCurDir[MAX_PATH];
  716. CHAR szVolumeLabel[MAX_PATH];
  717. // Manually put PrefixMap into Registry
  718. //
  719. // BUGBUG: cache containers are per user if user profiles are enabled
  720. // so on NT they are always per user, on Win95 however
  721. // Need to use HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE below
  722. // depending on what's enabled.
  723. //
  724. // Hack on top of a Hack for Win95 ONLY
  725. // Since this entire function is to workaround the lack of a param
  726. // for PrefixMap in CreateUrlCacheContainer() another hack shouldn't
  727. // matter since it's only temporary
  728. // On Win95 need to check this entry
  729. // HKEY_LOCAL_MACHINE\Network\Logon
  730. // UserProfiles=DWORD:00000001
  731. // which says if UserProfiles are turned on
  732. // If they are turned on we use HKEY_CURRENT_USER
  733. // otherwise use HKEY_LOCAL_MACHINE
  734. OSVERSIONINFO osvInfo;
  735. memset(&osvInfo, 0, sizeof(osvInfo));
  736. osvInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  737. if (GetVersionEx(&osvInfo))
  738. {
  739. if (VER_PLATFORM_WIN32_WINDOWS == osvInfo.dwPlatformId)
  740. {
  741. // We're running on Win95 so default to HKLM
  742. hKeyRoot = HKEY_LOCAL_MACHINE;
  743. }
  744. else
  745. hKeyRoot = HKEY_CURRENT_USER; // else assume NT and default to HKCU
  746. DWORD dwType = REG_DWORD;
  747. DWORD dwSize = sizeof(DWORD);
  748. DWORD dwUserProfiles = 0;
  749. HKEY hKeyProfiles = 0;
  750. // But now have to see if User Profiles are enabled
  751. if ((dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Network\\Logon",
  752. NULL, KEY_ALL_ACCESS, &hKeyProfiles)) == ERROR_SUCCESS)
  753. {
  754. if ((dwResult = RegQueryValueEx(hKeyProfiles, "UserProfiles",
  755. NULL, &dwType, (unsigned char *)&dwUserProfiles,
  756. &dwSize)) == ERROR_SUCCESS)
  757. {
  758. if ( (dwResult != ERROR_MORE_DATA) &&
  759. (1L == dwUserProfiles) )
  760. hKeyRoot = HKEY_CURRENT_USER;
  761. else
  762. hKeyRoot = HKEY_LOCAL_MACHINE;
  763. }
  764. }
  765. }
  766. if ( (dwResult = RegCreateKeyEx(hKeyRoot, szExtCacheRoot,
  767. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  768. NULL, &hKeyCacheExt, &dwDisposition)) == ERROR_SUCCESS)
  769. {
  770. if ( (dwResult = RegOpenKeyEx(hKeyCacheExt, lpszUniqueVendorName,
  771. 0, KEY_ALL_ACCESS, &hKeyVendor)) != ERROR_SUCCESS)
  772. {
  773. // Key didn't exist
  774. // Let's try to create it
  775. dwResult = RegCreateKeyEx(hKeyCacheExt, lpszUniqueVendorName,
  776. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  777. NULL, &hKeyVendor, &dwDisposition);
  778. }
  779. }
  780. if (dwResult == ERROR_SUCCESS)
  781. {
  782. RegSetValueEx(hKeyVendor, szKeyPrefixMap, 0, REG_SZ,
  783. (CONST UCHAR *) lpszPrefixMap, lstrlen(lpszPrefixMap)+1);
  784. RegSetValueEx(hKeyVendor, szKeyVolumeLabel, 0, REG_SZ,
  785. (CONST UCHAR *) lpszVolumeLabel, lstrlen(lpszVolumeLabel)+1);
  786. RegSetValueEx(hKeyVendor, szKeyVolumeTitle, 0, REG_SZ,
  787. (CONST UCHAR *) lpszVolumeTitle, lstrlen(lpszVolumeTitle)+1);
  788. }
  789. return dwResult;
  790. }
  791. /************************************************************************\
  792. * FUNCTION: GetPrefixMapEntry()
  793. *
  794. * Get the PrefixMap registry entry from the correct location in the
  795. * registry.
  796. *
  797. * Returns: PrefixMap entry in lpszPrefixMap
  798. * or NULL if no enty is found.
  799. *
  800. \************************************************************************/
  801. DWORD GetPrefixMapEntry(LPCSTR lpszUniqueVendorName, LPSTR lpszPrefixMap, DWORD cbPrefixMap)
  802. {
  803. const static char *szKeyPrefixMap = "PrefixMap";
  804. const static char *szExtCacheRoot = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Extensible Cache";
  805. HKEY hKeyRoot = HKEY_CURRENT_USER; // default to current user
  806. HKEY hKeyCacheExt = 0;
  807. HKEY hKeyVendor = 0;
  808. DWORD dwDisposition = 0;
  809. unsigned long ulVal = 0;
  810. DWORD dwResult = ERROR_SUCCESS;
  811. // Manually put PrefixMap into Registry
  812. //
  813. // BUGBUG: cache containers are per user if user profiles are enabled
  814. // so on NT they are always per user, on Win95 however
  815. // Need to use HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE below
  816. // depending on what's enabled.
  817. //
  818. // Hack on top of a Hack for Win95 ONLY
  819. // Since this entire function is to workaround the lack of a param
  820. // for PrefixMap in CreateUrlCacheContainer() another hack shouldn't
  821. // matter since it's only temporary
  822. // On Win95 need to check this entry
  823. // HKEY_LOCAL_MACHINE\Network\Logon
  824. // UserProfiles=DWORD:00000001
  825. // which says if UserProfiles are turned on
  826. // If they are turned on we use HKEY_CURRENT_USER
  827. // otherwise use HKEY_LOCAL_MACHINE
  828. OSVERSIONINFO osvInfo;
  829. memset(&osvInfo, 0, sizeof(osvInfo));
  830. osvInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  831. if (GetVersionEx(&osvInfo))
  832. {
  833. if (VER_PLATFORM_WIN32_WINDOWS == osvInfo.dwPlatformId)
  834. {
  835. // We're running on Win95 so default to HKLM
  836. hKeyRoot = HKEY_LOCAL_MACHINE;
  837. }
  838. else
  839. hKeyRoot = HKEY_CURRENT_USER; // else assume NT and default to HKCU
  840. DWORD dwType = REG_DWORD;
  841. DWORD dwSize = sizeof(DWORD);
  842. DWORD dwUserProfiles = 0;
  843. HKEY hKeyProfiles = 0;
  844. // But now have to see if User Profiles are enabled
  845. if ((dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Network\\Logon",
  846. NULL, KEY_ALL_ACCESS, &hKeyProfiles)) == ERROR_SUCCESS)
  847. {
  848. if ((dwResult = RegQueryValueEx(hKeyProfiles, "UserProfiles",
  849. NULL, &dwType, (unsigned char *)&dwUserProfiles,
  850. &dwSize)) == ERROR_SUCCESS)
  851. {
  852. if ( (dwResult != ERROR_MORE_DATA) &&
  853. (1L == dwUserProfiles) )
  854. hKeyRoot = HKEY_CURRENT_USER;
  855. else
  856. hKeyRoot = HKEY_LOCAL_MACHINE;
  857. }
  858. }
  859. }
  860. if ( (dwResult = RegCreateKeyEx(hKeyRoot, szExtCacheRoot,
  861. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  862. NULL, &hKeyCacheExt, &dwDisposition)) == ERROR_SUCCESS)
  863. {
  864. if ( (dwResult = RegOpenKeyEx(hKeyCacheExt, lpszUniqueVendorName,
  865. 0, KEY_ALL_ACCESS, &hKeyVendor)) != ERROR_SUCCESS)
  866. {
  867. // Key didn't exist
  868. lpszPrefixMap[0] = '\0';
  869. }
  870. else // key did exist so lets return it in lpszPrefixMap
  871. {
  872. // Vendor name must be unique so is it ok to assume uniqueness?
  873. if ( (dwResult = RegQueryValueEx(hKeyVendor, szKeyPrefixMap, 0, &ulVal,
  874. (LPBYTE) lpszPrefixMap, &cbPrefixMap ))
  875. == ERROR_SUCCESS )
  876. {
  877. }
  878. else
  879. lpszPrefixMap[0] = '\0';
  880. }
  881. }
  882. else
  883. lpszPrefixMap[0] = '\0';
  884. return dwResult;
  885. }
  886. /************************************************************************\
  887. * FUNCTION: WriteCacheContainerEntry()
  888. *
  889. * Manually write all the registry entries that WININET CreateUrlCacheContainer
  890. * would normally write.
  891. *
  892. * This f() is used when IE4 WININET is not yet installed.
  893. *
  894. \************************************************************************/
  895. DWORD WriteCacheContainerEntry(
  896. IN LPCSTR lpszUniqueVendorName,
  897. IN LPCSTR lpszCachePrefix,
  898. IN LPCSTR lpszPrefixMap, // New - part of WRAPPER
  899. IN LPCSTR lpszVolumeTitle, // New - part of WRAPPER
  900. IN LPCSTR lpszVolumeLabel, // New - part of WRAPPER
  901. IN DWORD KBCacheLimit,
  902. IN DWORD dwContainerType, // Not used by WININET currently
  903. IN DWORD dwOptions
  904. )
  905. {
  906. const static char *szCachePrefix = "CachePrefix";
  907. const static char *szKeyPrefixMap = "PrefixMap";
  908. const static char *szKeyVolumeLabel = "VolumeLabel";
  909. const static char *szKeyVolumeTitle = "VolumeTitle";
  910. const static char *szCacheLimit = "CacheLimit";
  911. const static char *szCacheOptions = "CacheOptions";
  912. const static char *szCachePath = "CachePath";
  913. const static char *szExtCacheRoot = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Extensible Cache";
  914. HKEY hKeyRoot = HKEY_CURRENT_USER; // default to current user
  915. HKEY hKeyCacheExt = 0;
  916. HKEY hKeyVendor = 0;
  917. DWORD dwDisposition = 0;
  918. DWORD dwResult = ERROR_SUCCESS;
  919. CHAR lpszCachePath[MAX_PATH];
  920. OSVERSIONINFO osvInfo;
  921. memset(&osvInfo, 0, sizeof(osvInfo));
  922. osvInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  923. if (GetVersionEx(&osvInfo))
  924. {
  925. if (VER_PLATFORM_WIN32_WINDOWS == osvInfo.dwPlatformId)
  926. {
  927. // We're running on Win95 so default to HKLM
  928. hKeyRoot = HKEY_LOCAL_MACHINE;
  929. }
  930. else
  931. hKeyRoot = HKEY_CURRENT_USER; // else assume NT and default to HKCU
  932. DWORD dwType = REG_DWORD;
  933. DWORD dwSize = sizeof(DWORD);
  934. DWORD dwUserProfiles = 0;
  935. HKEY hKeyProfiles = 0;
  936. BYTE bBuf[4096];
  937. LPINTERNET_CACHE_CONFIG_INFO lpCCI = (LPINTERNET_CACHE_CONFIG_INFO) bBuf;
  938. DWORD cbCEI = sizeof(bBuf);
  939. if (!lpfnGetUrlCacheConfigInfo)
  940. {
  941. HINSTANCE hDll;
  942. hDll = LoadLibrary("WININET.DLL");
  943. if (hDll != NULL)
  944. {
  945. lpfnGetUrlCacheConfigInfo = (LPFNGETURLCACHECONFIGINFO)GetProcAddress(hDll, "GetUrlCacheConfigInfoA");
  946. if (!lpfnGetUrlCacheConfigInfo)
  947. {
  948. FreeLibrary(hDll);
  949. dwResult = -1; // Indicate failure
  950. }
  951. }
  952. }
  953. if (lpfnGetUrlCacheConfigInfo)
  954. {
  955. // Figure out local user cache location directory
  956. // Note: Need to use IE3 backward compatible flag
  957. // IE3: CACHE_CONFIG_DISK_CACHE_PATHS_FC
  958. // IE4: CACHE_CONFIG_CONTENT_PATHS_FC
  959. if (lpfnGetUrlCacheConfigInfo(lpCCI, &cbCEI, CACHE_CONFIG_DISK_CACHE_PATHS_FC))
  960. {
  961. // Now need to parse the returned CachePath to remove trailing 'cache1\'
  962. // "c:\windows\Temporary Internet Files\cache1\"
  963. // look for backslash starting from end of string
  964. int i = lstrlen(lpCCI->CachePaths[0].CachePath);
  965. while( (lpCCI->CachePaths[0].CachePath[i] != '\\') && (i >= 0) )
  966. i--;
  967. if (lpCCI->CachePaths[0].CachePath[i] == '\\')
  968. lpCCI->CachePaths[0].CachePath[i+1] = '\0'; // Leave '\' intact for later strcat
  969. if (lpCCI->dwNumCachePaths > 0)
  970. lstrcpy(lpszCachePath, lpCCI->CachePaths[0].CachePath);
  971. // Add Cache Container Unique Vendor Name to CachePath
  972. // All container content will be stored in this location
  973. if(lstrlen(lpszCachePath) + lstrlen(lpszUniqueVendorName) >= sizeof(lpszCachePath) / sizeof(lpszCachePath[0]))
  974. {
  975. return FALSE;
  976. }
  977. lstrcat(lpszCachePath, lpszUniqueVendorName);
  978. }
  979. }
  980. else
  981. {
  982. // No IE3 or IE4 WININET present
  983. // so synthesize CachePath from GetWinDir() + "Temporary Internet Files"
  984. if ( GetWindowsDirectory(lpszCachePath, MAX_PATH) > 0)
  985. {
  986. if ('\\' == lpszCachePath[lstrlen(lpszCachePath)-1])
  987. lstrcat(lpszCachePath, _T("Temporary Internet Files"));
  988. else
  989. {
  990. lstrcat(lpszCachePath, _T("\\"));
  991. lstrcat(lpszCachePath, _T("Temporary Internet Files"));
  992. }
  993. }
  994. }
  995. // But now have to see if User Profiles are enabled
  996. if ((dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Network\\Logon",
  997. NULL, KEY_ALL_ACCESS, &hKeyProfiles)) == ERROR_SUCCESS)
  998. {
  999. if ((dwResult = RegQueryValueEx(hKeyProfiles, "UserProfiles",
  1000. NULL, &dwType, (unsigned char *)&dwUserProfiles,
  1001. &dwSize)) == ERROR_SUCCESS)
  1002. {
  1003. if ( (dwResult != ERROR_MORE_DATA) &&
  1004. (1L == dwUserProfiles) )
  1005. hKeyRoot = HKEY_CURRENT_USER;
  1006. else
  1007. hKeyRoot = HKEY_LOCAL_MACHINE;
  1008. }
  1009. }
  1010. }
  1011. if ( (dwResult = RegCreateKeyEx(hKeyRoot, szExtCacheRoot,
  1012. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  1013. NULL, &hKeyCacheExt, &dwDisposition)) == ERROR_SUCCESS)
  1014. {
  1015. if ( (dwResult = RegOpenKeyEx(hKeyCacheExt, lpszUniqueVendorName,
  1016. 0, KEY_ALL_ACCESS, &hKeyVendor)) != ERROR_SUCCESS)
  1017. {
  1018. // Key didn't exist
  1019. // Let's try to create it
  1020. dwResult = RegCreateKeyEx(hKeyCacheExt, lpszUniqueVendorName,
  1021. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  1022. NULL, &hKeyVendor, &dwDisposition);
  1023. }
  1024. }
  1025. if (dwResult == ERROR_SUCCESS)
  1026. {
  1027. RegSetValueEx(hKeyVendor, szKeyPrefixMap, 0, REG_SZ,
  1028. (CONST UCHAR *) lpszPrefixMap, lstrlen(lpszPrefixMap)+1);
  1029. RegSetValueEx(hKeyVendor, szKeyVolumeLabel, 0, REG_SZ,
  1030. (CONST UCHAR *) lpszVolumeLabel, lstrlen(lpszVolumeLabel)+1);
  1031. RegSetValueEx(hKeyVendor, szKeyVolumeTitle, 0, REG_SZ,
  1032. (CONST UCHAR *) lpszVolumeTitle, lstrlen(lpszVolumeTitle)+1);
  1033. RegSetValueEx(hKeyVendor, szCachePrefix, 0, REG_SZ,
  1034. (CONST UCHAR *) lpszCachePrefix, lstrlen(lpszCachePrefix)+1);
  1035. RegSetValueEx(hKeyVendor, szCachePath, 0, REG_SZ,
  1036. (CONST UCHAR *) lpszCachePath, lstrlen(lpszCachePath)+1);
  1037. RegSetValueEx(hKeyVendor, szCacheLimit, 0, REG_DWORD,
  1038. (unsigned char *)&KBCacheLimit, sizeof(DWORD));
  1039. RegSetValueEx(hKeyVendor, szCacheOptions, 0, REG_DWORD,
  1040. (unsigned char *)&dwOptions, sizeof(DWORD));
  1041. }
  1042. if (dwResult != ERROR_SUCCESS)
  1043. return (FALSE);
  1044. else
  1045. return (TRUE);
  1046. }
  1047. /************************************************************************\
  1048. * FUNCTION: CacheContainer()
  1049. *
  1050. * Parameters:
  1051. * dwAction - flag indicating what to do
  1052. * CACHE_ACTION_INSTALL
  1053. * CACHE_ACTION_REMOVE
  1054. * CACHE_ACTION_FILL_LB
  1055. *
  1056. * hListBox - HWND to ListBox to fill in with Container names
  1057. *
  1058. *
  1059. * Note:
  1060. * if dwAction == CACHE_ACTION_FILL_LB then if hListBox
  1061. * is NULL then return TRUE if ALL Containers installed
  1062. * correctly or FALSE if not
  1063. *
  1064. * Additionally create a CDCACHE.INF at the root of the CD-ROM.
  1065. * Typical contents:
  1066. *
  1067. * [Add.CacheContainer]
  1068. * <Unique Vendor Name>=<INF Section Name>
  1069. * Encarta 97=EncartaCD
  1070. *
  1071. * [INF Section Name]
  1072. * VolumeLabel=<string>
  1073. * VolumeTitle=<string>
  1074. * CachePrefix=<string>
  1075. * CacheRoot=<relative path on CD-ROM of data>
  1076. * KBCacheLimit=<numerical amount in KB>
  1077. * AutoDelete=Yes|No (default)
  1078. * IncludeSubDirs=Yes|No (default)
  1079. * NoDesktopInit=Yes|No (default)
  1080. *
  1081. * [EncartaCD]
  1082. * VolumeLabel=MSENCART97
  1083. * VolumeTitle=Microsoft Encarta CD 97
  1084. * CachePrefix=http://www.microsoft.com/encarta
  1085. * CacheRoot=%EXE_ROOT%\data\http
  1086. * KBCacheLimit=500
  1087. * AutoDelete=Yes
  1088. * IncludeSubDirs=Yes
  1089. *
  1090. * NOTE: %EXE_ROOT% is a replaceable param that gets set to the
  1091. * path this EXE was ran from, such as E: or E:\BIN
  1092. *
  1093. *
  1094. * Calls _CreateUrlCacheContainer()
  1095. \************************************************************************/
  1096. BOOL CacheContainer(DWORD *dwTotal, DWORD *dwInstalled, DWORD dwAction, HWND hListBox)
  1097. {
  1098. BOOL bRet = FALSE;
  1099. BOOL bVolumeLabel = FALSE;
  1100. DWORD dwRes = 0;
  1101. HRESULT hr = 0;
  1102. int nSectionSize = 4096; // Limit each INF section to 4K
  1103. char szSections[4096];
  1104. char *lpSections = (char *)szSections;
  1105. const static char *szAddCacheContainerSection = "Add.CacheContainer";
  1106. const static char *szKey_Name = "Name";
  1107. const static char *szKey_VolumeTitle = "VolumeTitle";
  1108. const static char *szKey_Prefix = "CachePrefix";
  1109. const static char *szKey_Root = "CacheRoot";
  1110. const static char *szKey_CacheLimit = "KBCacheLimit";
  1111. const static char *szKey_AutoDelete = "AutoDelete";
  1112. const static char *szKey_IncludeSubDirs = "IncludeSubDirs";
  1113. const static char *szKey_NoDesktopInit = "NoDesktopInit";
  1114. char szDefault[12] = "*Unknown*"; // note: buffer needs to hold larger strings
  1115. DWORD len;
  1116. char szInf[STRING_BUFFER_SIZE];
  1117. char szInfPath[MAX_PATH];
  1118. char szContainerName[STRING_BUFFER_SIZE];
  1119. char szCachePrefix[STRING_BUFFER_SIZE];
  1120. char szCacheRoot[MAX_PATH];
  1121. char szPrefixMap[MAX_PATH];
  1122. char szVolumeLabel[MAX_PATH];
  1123. char szMapDrive[4];
  1124. char szVolumeTitle[MAX_PATH];
  1125. char szAutoDelete[STRING_BUFFER_SIZE];
  1126. char szIncludeSubDirs[STRING_BUFFER_SIZE];
  1127. char szNoDesktopInit[STRING_BUFFER_SIZE];
  1128. int nDefault = 0;
  1129. int nCacheLimit = 0;
  1130. BOOL bResult;
  1131. HANDLE hFile;
  1132. #define SIZE_CMD_LINE 2048
  1133. char szBuf[SIZE_CMD_LINE]; // enough for commandline
  1134. // BEGIN NOTE: add vars and values in matching order
  1135. // add a var by adding a new define VAR_NEW_VAR = NUM_VARS++
  1136. const char *szVars[] =
  1137. {
  1138. #define VAR_EXE_ROOT 0 // Replace with drive+path (ex. "D:" or "D:\PATH") of this EXE
  1139. "%EXE_ROOT%",
  1140. #define VAR_EXE_DRIVE 1 // Replace with drive (ex. "D:") of this EXE
  1141. "%EXE_DRIVE%",
  1142. #define NUM_VARS 2
  1143. ""
  1144. };
  1145. int nValBuffSize = MAX_PATH;
  1146. char lpValBuffer[MAX_PATH];
  1147. int nDriveBuffSize = MAX_PATH;
  1148. char lpDriveBuffer[MAX_PATH];
  1149. const char *szValues[NUM_VARS + 1];
  1150. szValues[VAR_EXE_ROOT] = GetINFDir(lpValBuffer, nValBuffSize);
  1151. szValues[VAR_EXE_DRIVE] = GetINFDrive(lpDriveBuffer, nDriveBuffSize);
  1152. szValues[NUM_VARS] = NULL;
  1153. // END NOTE: add vars and values in matching order
  1154. CWaitCursor wait;
  1155. // Look for INF
  1156. //
  1157. LoadString (g_hInst, ID_INFNAME, szInf, sizeof(szInf));
  1158. lstrcpy(szInfPath, GetINFDir(szInfPath, sizeof(szInfPath)) );
  1159. strcat (szInfPath, "\\");
  1160. strcat (szInfPath, szInf);
  1161. strcat (szInfPath, ".INF");
  1162. hFile = CreateFile(szInfPath, GENERIC_READ, FILE_SHARE_READ, NULL,
  1163. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1164. if (INVALID_HANDLE_VALUE != hFile)
  1165. {
  1166. CloseHandle(hFile);
  1167. hFile = NULL;
  1168. // Is there a [Add.CacheContainer] section
  1169. // BUGBUG: GetPrivateProfileSection() fails on Win95
  1170. // Workaround for GetPrivateProfileSection() failure on Win95
  1171. szDefault[0] = '\0';
  1172. len = GetPrivateProfileString(szAddCacheContainerSection, NULL, szDefault,
  1173. lpSections, nSectionSize, szInfPath);
  1174. if (!len)
  1175. {
  1176. // no CD-ROM Cache Container sections in INF
  1177. // BUGBUG: Display a message if in NON Silent mode?
  1178. // This is case where AUTORUN.INF has no [Add.Container] section
  1179. }
  1180. else
  1181. {
  1182. // lpBuffer now has list of key strings (as in key=value)
  1183. // final pair terminated with extra NULL
  1184. //
  1185. // Loop through each cache container entry
  1186. while (*lpSections)
  1187. {
  1188. WORD dResult = 0;
  1189. // Init flags for this container to map-able.
  1190. DWORD dwOptions = INTERNET_CACHE_CONTAINER_MAP_ENABLED;
  1191. GetPrivateProfileString(szAddCacheContainerSection, lpSections, szDefault,
  1192. szContainerName, STRING_BUFFER_SIZE, szInfPath);
  1193. if (szContainerName)
  1194. {
  1195. (*dwTotal)++; // Keep track of how many cache containers in INF
  1196. // Build PrefixMap
  1197. //
  1198. // BUGBUG: Default to root?
  1199. lstrcpy(szDefault, "%EXE_ROOT%");
  1200. // Get the PrefixMap entry
  1201. dwRes = GetPrivateProfileString(szContainerName, szKey_Root, szDefault,
  1202. szCacheRoot, MAX_PATH, szInfPath);
  1203. // Replace any %parameters%
  1204. // S_OK indicates that something was expanded
  1205. if (S_OK == (hr = ExpandEntry(szCacheRoot, szBuf, SIZE_CMD_LINE, szVars, szValues)))
  1206. lstrcpyn(szPrefixMap, szBuf, sizeof(szPrefixMap));
  1207. else
  1208. lstrcpy(szPrefixMap, szCacheRoot);
  1209. memcpy(szMapDrive, szPrefixMap, 2);
  1210. memcpy(szMapDrive + 2, "\\", sizeof("\\"));
  1211. if (GetVolumeInformation(szMapDrive, szVolumeLabel, MAX_PATH,
  1212. NULL, NULL, NULL, NULL, 0))
  1213. {
  1214. bVolumeLabel = TRUE;
  1215. }
  1216. else
  1217. {
  1218. *szVolumeLabel = '\0';
  1219. bVolumeLabel = FALSE;
  1220. }
  1221. lstrcpy(szDefault, "");
  1222. GetPrivateProfileString(szContainerName, szKey_Prefix, szDefault,
  1223. szCachePrefix, STRING_BUFFER_SIZE, szInfPath);
  1224. lstrcpy(szDefault, "");
  1225. GetPrivateProfileString(szContainerName, szKey_VolumeTitle, szDefault,
  1226. szVolumeTitle, STRING_BUFFER_SIZE, szInfPath);
  1227. // Now trim off trailing backslash '\' from szCachePrefix
  1228. // workaround for #43375
  1229. int i = lstrlen(szCachePrefix);
  1230. if (i > 0)
  1231. if ('\\' == szCachePrefix[i - 1])
  1232. szCachePrefix[i - 1] = '\0';
  1233. // BUGBUG: Should create custom Profile f() to
  1234. // read/return DWORD value rather than int
  1235. nDefault = 500; // 500K Cache Limit
  1236. nCacheLimit = GetPrivateProfileInt(szContainerName, szKey_CacheLimit,
  1237. nDefault, szInfPath);
  1238. dResult = GetProfileBooleanWord(szContainerName, szKey_AutoDelete, szInfPath);
  1239. switch (dResult)
  1240. {
  1241. case -1: // The key did not exist in INF
  1242. break; // default is No/False for AutoDelete
  1243. case FALSE:
  1244. break;
  1245. case TRUE:
  1246. dwOptions |= INTERNET_CACHE_CONTAINER_AUTODELETE;
  1247. break;
  1248. }
  1249. dResult = GetProfileBooleanWord(szContainerName, szKey_IncludeSubDirs, szInfPath);
  1250. switch (dResult)
  1251. {
  1252. case -1: // The key did not exist in INF
  1253. break; // default is Yes/True for IncludeSubDirs
  1254. case FALSE:
  1255. dwOptions |= INTERNET_CACHE_CONTAINER_NOSUBDIRS; // Don't include subdirs in cacheview
  1256. break;
  1257. case TRUE:
  1258. break;
  1259. }
  1260. dResult = GetProfileBooleanWord(szContainerName, szKey_NoDesktopInit, szInfPath);
  1261. switch (dResult)
  1262. {
  1263. case -1: // The key did not exist in INF
  1264. break; // default is No/False for NoDesktopInit
  1265. case FALSE:
  1266. break;
  1267. case TRUE:
  1268. dwOptions |= INTERNET_CACHE_CONTAINER_NODESKTOPINIT;
  1269. break;
  1270. }
  1271. switch (dwAction)
  1272. {
  1273. case CACHE_ACTION_INSTALL:
  1274. // Call CreateUrlCacheContainer WRAPPER
  1275. if (bVolumeLabel)
  1276. {
  1277. bRet = _CreateUrlCacheContainer(lpSections, szCachePrefix, szPrefixMap,
  1278. szVolumeTitle, szVolumeLabel, nCacheLimit, 0, dwOptions);
  1279. }
  1280. else
  1281. {
  1282. bRet = FALSE;
  1283. }
  1284. break;
  1285. case CACHE_ACTION_REMOVE:
  1286. if (!WininetLoaded())
  1287. return FALSE;
  1288. bRet = lpfnDeleteUrlCacheContainer(lpSections, dwOptions);
  1289. break;
  1290. case CACHE_ACTION_FILL_LB:
  1291. // Fill listbox hListBox
  1292. if (hListBox)
  1293. {
  1294. SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)lpSections);
  1295. }
  1296. else
  1297. {
  1298. // hListBox is NULL
  1299. //
  1300. // if dwAction == CACHE_ACTION_FILL_LB then if hListBox
  1301. // is NULL then return TRUE if ALL Containers installed
  1302. // correctly or FALSE if not
  1303. //
  1304. if (UrlCacheContainerExists(lpSections, szCachePrefix, szPrefixMap))
  1305. bRet = TRUE;
  1306. else
  1307. return FALSE; // One container is not installed so bail out
  1308. }
  1309. break;
  1310. case CACHE_ACTION_MAKE_REG_ENTRIES:
  1311. if (bVolumeLabel)
  1312. {
  1313. bRet = WriteCacheContainerEntry(lpSections, szCachePrefix, szPrefixMap, szVolumeTitle,
  1314. szVolumeLabel, nCacheLimit, 0, dwOptions);
  1315. }
  1316. else
  1317. bRet = FALSE;
  1318. break;
  1319. }
  1320. if (bRet)
  1321. (*dwInstalled)++; // Keep track of successful installs
  1322. }
  1323. //else empty section entry, ignore and move to next
  1324. // Get Next Section name
  1325. while ( (*(lpSections++) != '\0') );
  1326. }
  1327. }
  1328. }
  1329. else
  1330. {
  1331. // Couldn't find INF file
  1332. // BUGBUG: need to do anything else here?
  1333. }
  1334. return bRet;
  1335. }
  1336. /************************************************************************\
  1337. * FUNCTION: ExpandEntry()
  1338. *
  1339. * Borrowed from urlmon\download\hooks.cxx
  1340. \************************************************************************/
  1341. HRESULT ExpandEntry(
  1342. LPSTR szSrc,
  1343. LPSTR szBuf,
  1344. DWORD cbBuffer,
  1345. const char * szVars[],
  1346. const char * szValues[])
  1347. {
  1348. //Assert(szSrc);
  1349. HRESULT hr = S_FALSE;
  1350. LPSTR pchSrc = szSrc; // start parsing at begining of cmdline
  1351. LPSTR pchOut = szBuf; // set at begin of out buffer
  1352. DWORD cbLen = 0;
  1353. while (*pchSrc) {
  1354. // look for match of any of our env vars
  1355. if (*pchSrc == '%') {
  1356. HRESULT hr1 = ExpandVar(pchSrc, pchOut, cbLen, // all passed by ref!
  1357. cbBuffer, szVars, szValues);
  1358. if (FAILED(hr1)) {
  1359. hr = hr1;
  1360. goto Exit;
  1361. }
  1362. if (hr1 == S_OK) { // expand var expanded this
  1363. hr = hr1;
  1364. continue;
  1365. }
  1366. }
  1367. // copy till the next % or nul
  1368. if ((cbLen + 1) < cbBuffer) {
  1369. *pchOut++ = *pchSrc++;
  1370. cbLen++;
  1371. } else {
  1372. // out of buffer space
  1373. *pchOut = '\0'; // term
  1374. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1375. goto Exit;
  1376. }
  1377. }
  1378. *pchOut = '\0'; // term
  1379. Exit:
  1380. return hr;
  1381. }
  1382. /************************************************************************\
  1383. * FUNCTION: ExpandVar()
  1384. *
  1385. * Borrowed from urlmon\download\hooks.cxx
  1386. \************************************************************************/
  1387. HRESULT ExpandVar(
  1388. LPSTR& pchSrc, // passed by ref!
  1389. LPSTR& pchOut, // passed by ref!
  1390. DWORD& cbLen, // passed by ref!
  1391. DWORD cbBuffer,
  1392. const char * szVars[],
  1393. const char * szValues[])
  1394. {
  1395. HRESULT hr = S_FALSE;
  1396. int cbvar = 0;
  1397. //Assert (*pchSrc == '%');
  1398. for (int i=0; szVars[i] && (cbvar = lstrlen(szVars[i])) ; i++) { // for each variable
  1399. int cbneed = 0;
  1400. if ( (szValues[i] == NULL) || !(cbneed = lstrlen(szValues[i])))
  1401. continue;
  1402. cbneed++; // add for nul
  1403. if (0 == strncmp(szVars[i], pchSrc, cbvar)) {
  1404. // found something we can expand
  1405. if ((cbLen + cbneed) >= cbBuffer) {
  1406. // out of buffer space
  1407. *pchOut = '\0'; // term
  1408. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1409. goto Exit;
  1410. }
  1411. lstrcpy(pchOut, szValues[i]);
  1412. cbLen += (cbneed -1); //don't count the nul
  1413. pchSrc += cbvar; // skip past the var in pchSrc
  1414. pchOut += (cbneed -1); // skip past dir in pchOut
  1415. hr = S_OK;
  1416. goto Exit;
  1417. }
  1418. }
  1419. Exit:
  1420. return hr;
  1421. }
  1422. // Return drive+path without trailing backslash
  1423. LPSTR GetINFDir(LPSTR lpBuffer, int nBuffSize)
  1424. {
  1425. // Figure out what directory we've been started in
  1426. GetModuleFileName(g_hInst, lpBuffer, nBuffSize);
  1427. // Now trim off trailing backslash '\' if any
  1428. int i = lstrlen(lpBuffer);
  1429. if (i > 0)
  1430. if ('\\' == lpBuffer[i - 1])
  1431. lpBuffer[i - 1] = '\0';
  1432. // Get rid of executable name
  1433. i = lstrlen(lpBuffer);
  1434. while( (lpBuffer[i] != '\\') && (i >= 0) )
  1435. i--;
  1436. if (lpBuffer[i] == '\\')
  1437. lpBuffer[i] = '\0';
  1438. return lpBuffer;
  1439. }
  1440. // Return drive without trailing backslash
  1441. LPSTR GetINFDrive(LPSTR lpBuffer, int nBuffSize)
  1442. {
  1443. // Figure out what directory we've been started in
  1444. GetModuleFileName(g_hInst, lpBuffer, nBuffSize);
  1445. if (!lpBuffer)
  1446. return NULL;
  1447. LPSTR lpSaveBuffer = lpBuffer;
  1448. // Now trim off everything after first colon ':'
  1449. if (':' == lpBuffer[1])
  1450. lpBuffer[2] = '\0';
  1451. else
  1452. {
  1453. // assumption that lpBuffer of form "D:\path" failed
  1454. // so actually parse it
  1455. // #48022 robgil - add check for end of lpBuffer string
  1456. while (*lpBuffer != '\0' && *lpBuffer != ':')
  1457. lpBuffer++;
  1458. if (':' == *lpBuffer)
  1459. *(lpBuffer + 1) = '\0';
  1460. else
  1461. {
  1462. // #48022
  1463. // Need to return \\server\share
  1464. // for Drive when a UNC path
  1465. lpBuffer = lpSaveBuffer;
  1466. if ('\\' == lpBuffer[0] && '\\' == lpBuffer[1])
  1467. {
  1468. lpBuffer += 2; // move past leading '\\'
  1469. while (*lpBuffer != '\0' && *lpBuffer != '\\')
  1470. lpBuffer++;
  1471. if ('\\' == *lpBuffer)
  1472. {
  1473. lpBuffer++;
  1474. while (*lpBuffer != '\0' && *lpBuffer != '\\')
  1475. lpBuffer++;
  1476. if ('\\' == *lpBuffer)
  1477. *lpBuffer = '\0';
  1478. }
  1479. }
  1480. }
  1481. }
  1482. return lpSaveBuffer;
  1483. }
  1484. //------------------------------------------------------------------------
  1485. // BOOL GetProfileBooleanWord
  1486. //
  1487. // Description:
  1488. // Retrieves the value associated with szKeyName and
  1489. // evaluates to a TRUE or FALSE. If a value is not
  1490. // associated with the key, -1 is returned.
  1491. //
  1492. // Parameters:
  1493. // LPSTR szKeyName
  1494. // pointer to key name
  1495. //
  1496. // Return Value:
  1497. // WORD
  1498. // -1, if a setting for the given key does not exist
  1499. // TRUE, if value evaluates to a "positive" or "true"
  1500. // FALSE, otherwise
  1501. //
  1502. //------------------------------------------------------------------------
  1503. WORD GetProfileBooleanWord
  1504. (
  1505. LPCTSTR szIniSection,
  1506. LPCTSTR szKeyName,
  1507. LPCTSTR szIniFile
  1508. )
  1509. {
  1510. TCHAR szTemp[10];
  1511. GetPrivateProfileString( szIniSection,
  1512. szKeyName, _T(""), szTemp, sizeof( szTemp ),
  1513. szIniFile ) ;
  1514. if (0 == lstrlen( szTemp ))
  1515. return ( (WORD) -1 ) ;
  1516. if ((0 == lstrcmpi( szTemp, gszIniValTrue )) ||
  1517. (0 == lstrcmpi( szTemp, gszIniValYes )) ||
  1518. (0 == lstrcmpi( szTemp, gszIniValOn )))
  1519. return ( TRUE ) ;
  1520. // Try and convert something numeric
  1521. if (0 != _ttoi(szTemp)) // atoi (via tchar.h)
  1522. return ( TRUE );
  1523. return ( FALSE ) ;
  1524. } // end of GetProfileBooleanWord()