/******************************************************************************\ * * CDCACHE.EXE * * Synopsis: * An AutoRun EXE to enable easy addition of CD-ROM content * into the Internet Explorer (WININET) Persistent URL Cache. * * Usage: * Place an AUTORUN.INF at the root of the CD-ROM which has content * that you want to register with the WININET Persistent URL Cache. * Contents of AUTORUN.INF: * * [autorun] * open=cdcache.exe * icon=cdcache.exe, 1 * * Additionally create a CDCACHE.INF at the root of the CD-ROM. * Typical contents: * * [Add.CacheContainer] * = * * [INF Section Name] * CachePrefix= * CacheRoot= * KBCacheLimit= * AutoDelete=Yes|No (default) * IncludeSubDirs=Yes (default) |No * NoDesktopInit=Yes|No (default) * * * CMD Line Options: * /Silent Install Cache Container without showing UI * /Remove Uninstall the cache container * /Uninstall same as /Remove * * History * 23June97 robgil created * 06Aug97 robgil add IE4 wininet.dll checks * 26Aug97 robgil manual register if no IE4 * * Copyright (C) 1994-1997 Microsoft Corporation. * All rights reserved. * \******************************************************************************/ #include "stdhdr.h" ///////////////////////////////////////////////////////////////////////// // Defines and Type Declarations #define STRING_BUFFER_SIZE 256 #define CACHE_ACTION_INSTALL 0 #define CACHE_ACTION_REMOVE 1 #define CACHE_ACTION_FILL_LB 2 #define CACHE_ACTION_MAKE_REG_ENTRIES 3 typedef BOOL (CALLBACK* LPFNCREATEURLCACHECONTAINER)(LPCSTR,LPCSTR,LPCSTR,DWORD,DWORD,DWORD,LPVOID,LPDWORD); typedef BOOL (CALLBACK* LPFNDELETEURLCACHECONTAINER)(LPCSTR,DWORD); typedef HANDLE (CALLBACK* LPFNFINDFIRSTURLCACHECONTAINER)(LPDWORD,LPINTERNET_CACHE_CONTAINER_INFO,LPDWORD,DWORD); typedef BOOL (CALLBACK* LPFNFINDNEXTURLCACHECONTAINER)(HANDLE,LPINTERNET_CACHE_CONTAINER_INFO,LPDWORD); typedef BOOL (CALLBACK* LPFNFINDCLOSEURLCACHE)(HANDLE); typedef BOOL (CALLBACK* LPFNGETURLCACHECONFIGINFO)(LPINTERNET_CACHE_CONFIG_INFO,LPDWORD,DWORD); ///////////////////////////////////////////////////////////////////////// // Global Variables: HINSTANCE g_hInst; // current instance BOOL g_fRunSilent = FALSE; // True = show no UI BOOL g_fRemove = FALSE; // True = remove the cache containers in INF //BOOL g_fNoIE4Msg = FALSE; // True = do not show UI saying IE4 WININET is required BOOL g_fNoIE4 = FALSE; // IE4 WININET is not available TCHAR gszIniValTrue[] = INI_TRUE ; TCHAR gszIniValFalse[] = INI_FALSE ; TCHAR gszIniValOn[] = INI_ON ; TCHAR gszIniValOff[] = INI_OFF ; TCHAR gszIniValYes[] = INI_YES ; TCHAR gszIniValNo[] = INI_NO ; LPFNCREATEURLCACHECONTAINER lpfnCreateUrlCacheContainer = NULL; LPFNDELETEURLCACHECONTAINER lpfnDeleteUrlCacheContainer = NULL; LPFNFINDFIRSTURLCACHECONTAINER lpfnFindFirstUrlCacheContainer = NULL; LPFNFINDNEXTURLCACHECONTAINER lpfnFindNextUrlCacheContainer = NULL; LPFNFINDCLOSEURLCACHE lpfnFindCloseUrlCache = NULL; LPFNGETURLCACHECONFIGINFO lpfnGetUrlCacheConfigInfo = NULL; ///////////////////////////////////////////////////////////////////////// // Foward declarations of functions included in this code module: INT_PTR CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM); BOOL CenterWindow (HWND, HWND); int OnInitDialog(HWND hDlg); BOOL LoadWininet(void); BOOL WininetLoaded(void); BOOL CacheContainer(DWORD *dwTotal, DWORD *dwInstalled, DWORD dwAction, HWND hListBox); HRESULT ExpandEntry( LPSTR szSrc, LPSTR szBuf, DWORD cbBuffer, const char * szVars[], const char * szValues[]); HRESULT ExpandVar( LPSTR& pchSrc, // passed by ref! LPSTR& pchOut, // passed by ref! DWORD& cbLen, // passed by ref! DWORD cbBuffer, // size of out buffer const char * szVars[], // array of variable names eg. %EXE_ROOT% const char * szValues[]);// corresponding values to expand of vars LPSTR GetINFDir(LPSTR lpBuffer, int nBuffSize); LPSTR GetINFDrive(LPSTR lpBuffer, int nBuffSize); WORD GetProfileBooleanWord(LPCTSTR szIniSection, LPCTSTR szKeyName, LPCTSTR szIniFile); DWORD CreateAdditionalEntries(LPCSTR lpszUniqueVendorName, LPCSTR lpszVolumeTitle, LPCSTR lpszVolumeLabel, LPCSTR lpszPrefixMap); DWORD GetPrefixMapEntry(LPCSTR lpszUniqueVendorName, LPSTR lpszPrefixMap, DWORD cbPrefixMap); BOOL UrlCacheContainerExists(LPCSTR lpszUniqueVendorName, LPCSTR lpszCachePrefix, LPCSTR lpszPrefixMap); // WININET CreateUrlCacheContainer WRAPPER // Wraps up the hacks in one spot - see f() header for details BOOL _CreateUrlCacheContainer( IN LPCSTR lpszUniqueVendorName, IN LPCSTR lpszCachePrefix, IN LPCSTR lpszPrefixMap, // New - part of WRAPPER IN LPCSTR lpszVolumeTitle, // New - part of WRAPPER IN LPCSTR lpszVolumeLabel, // New - part of Wrapper. IN DWORD KBCacheLimit, IN DWORD dwContainerType, IN DWORD dwOptions ); /************************************************************************\ * FUNCTION: WinMain \************************************************************************/ int APIENTRY WinMain(HINSTANCE g_hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { LPSTR lpszCmd = NULL; DWORD dwTotal = 0; DWORD dwInstalled = 0; g_hInst = g_hInstance; // Parse lpCmdLine looking for options we understand TCHAR szTokens[] = _T("-/ "); LPTSTR lpszToken = _tcstok(lpCmdLine, szTokens); while (lpszToken != NULL) { if (_tcsicmp(lpszToken, _T("Silent"))==0) g_fRunSilent = TRUE; else if (_tcsicmp(lpszToken, _T("Remove"))==0) g_fRemove = TRUE; else if (_tcsicmp(lpszToken, _T("Uninstall"))==0) g_fRemove = TRUE; // else if (_tcsicmp(lpszToken, _T("NoIE4Msg"))==0) // g_fNoIE4Msg = TRUE; lpszToken = _tcstok(NULL, szTokens); } // Check for IE4 or higher WININET.DLL version // and dynamically load it and init global function pointers // to WININET f() used in this application // This will avoid Undefined Dynalink errors when run on a // system without IE4 if (!LoadWininet()) { g_fNoIE4 = TRUE; // Put up message about requiring IE4 WININET /* Since we workaround not having IE4 - no need for message if (!g_fNoIE4Msg) { char szString[128]; // Keep string 70% larger for localization char szCaption[128]; // Keep string 70% larger for localization LoadString (g_hInst, ID_APPNAME, szCaption, sizeof(szCaption)); LoadString (g_hInst, IDM_NEEDIE4WININET, szString, sizeof(szString)); MessageBox(NULL, szString, szCaption, MB_OK); } */ // Can't call WININET // Need to make registry entries to install cache containers // if (!CacheContainer(&dwTotal, &dwInstalled, CACHE_ACTION_FILL_LB, NULL)) { if (g_fRunSilent) { // Create cache entries in silent mode. CacheContainer(&dwTotal, &dwInstalled, CACHE_ACTION_MAKE_REG_ENTRIES, NULL); } else { // Otherwise run app. DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_MAINAPP), NULL, DlgProc); } return(FALSE); } return 0; // Quit and go home } if (!g_fRunSilent) { // Only want to put up UI if any of the containers are NOT installed // (this includes those containers that are installed but the // PrefixMap entry is incorrect - i.e. wrong drive) if (!CacheContainer(&dwTotal, &dwInstalled, CACHE_ACTION_FILL_LB, NULL)) { DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_MAINAPP), NULL, DlgProc); return(FALSE); } else { // All the CacheContainers are already installed or there is no INF // so check if we want to uninstall // OnInitDialog checks the g_fRemove flags and POST's a msg // to dialog to initiate the Uninstall steps if (g_fRemove) DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_MAINAPP), NULL, DlgProc); } } else { DWORD dwAction = CACHE_ACTION_INSTALL; // default action is INSTALL // We're running silent and deep - all quiet on board // we don't need no stinkin window if (g_fRemove) dwAction = CACHE_ACTION_REMOVE; if (!CacheContainer(&dwTotal, &dwInstalled, dwAction, NULL)) { // BUGBUG: Since we're running silent what // should we do on failure? } return 0; } return 0; } /************************************************************************\ * FUNCTION: DlgProc \************************************************************************/ INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; switch (message) { case WM_INITDIALOG: return OnInitDialog(hDlg); case WM_COMMAND: wmId = LOWORD(wParam); // Remember, these are... wmEvent = HIWORD(wParam); // ...different for Win32! switch (wmId) { case IDM_INSTALL: { DWORD dwError = 0; DWORD dwTotal = 0; DWORD dwInstalled = 0; DWORD dwAction = 0; if (g_fNoIE4) dwAction = CACHE_ACTION_MAKE_REG_ENTRIES; else dwAction = CACHE_ACTION_INSTALL; if (!CacheContainer(&dwTotal, &dwInstalled, dwAction, NULL)) { dwError = GetLastError(); } if (dwInstalled > 0) { char szString[128]; // Keep string 70% larger for localization char szBuffer[256]; // Successfully installed a cache container // though not necessarily all of them. LoadString (g_hInst, IDM_SUCCESS, szString, sizeof(szString)); wsprintf(szBuffer, szString, dwInstalled, dwTotal); LoadString (g_hInst, ID_APPNAME, szString, sizeof(szString)); MessageBox(hDlg, szBuffer, szString, MB_OK); // We're done close this app PostMessage (hDlg, WM_CLOSE, 0, 0); } else { char szString[128]; // Keep string 70% larger for localization char szBuffer[256]; // Unable to install any of the cache containers successfully LoadString (g_hInst, IDM_FAILED, szString, sizeof(szString)); wsprintf(szBuffer, szString, dwTotal); LoadString (g_hInst, ID_APPNAME, szString, sizeof(szString)); MessageBox(hDlg, szBuffer, szString, MB_OK); } break; } case IDM_UNINSTALL: { DWORD dwError = 0; DWORD dwTotal = 0; DWORD dwRemoved = 0; if (g_fNoIE4) { char szString[128]; // Keep string 70% larger for localization char szBuffer[256]; // Uninstall of cache containers requires IE4 LoadString (g_hInst, IDM_ERR_IE4REQFORUNINSTALL, szString, sizeof(szString)); wsprintf(szBuffer, szString, dwRemoved, dwTotal); LoadString (g_hInst, ID_APPNAME, szString, sizeof(szString)); MessageBox(hDlg, szBuffer, szString, MB_OK); } else { if (!CacheContainer(&dwTotal, &dwRemoved, CACHE_ACTION_REMOVE, NULL)) { dwError = GetLastError(); } if (dwRemoved > 0) { char szString[128]; // Keep string 70% larger for localization char szBuffer[256]; // Successfully UnInstalled a cache container // though not necessarily all of them. LoadString (g_hInst, IDM_SUCCESS_REMOVE, szString, sizeof(szString)); wsprintf(szBuffer, szString, dwRemoved, dwTotal); LoadString (g_hInst, ID_APPNAME, szString, sizeof(szString)); MessageBox(hDlg, szBuffer, szString, MB_OK); } else { char szString[128]; // Keep string 70% larger for localization char szBuffer[256]; // Unable to install any of the cache containers successfully LoadString (g_hInst, IDM_FAILED_REMOVE, szString, sizeof(szString)); wsprintf(szBuffer, szString, dwTotal); LoadString (g_hInst, ID_APPNAME, szString, sizeof(szString)); MessageBox(hDlg, szBuffer, szString, MB_OK); } } if (g_fRemove) { // We're done close this app PostMessage (hDlg, WM_CLOSE, 0, 0); } break; } case IDCANCEL: EndDialog(hDlg, TRUE); break; default: return (FALSE); } break; default: return (FALSE); } return (TRUE); } /************************************************************************\ * FUNCTION: CenterWindow \************************************************************************/ // This is a 'utility' function I find usefull. It will center one // window over another. It also makes sure that the placement is within // the 'working area', meaning that it is both within the display limits // of the screen, -and- not obscured by the tray or other frameing // elements of the desktop. BOOL CenterWindow (HWND hwndChild, HWND hwndParent) { RECT rChild, rParent, rWorkArea = {0,0,0,0}; int wChild, hChild, wParent, hParent; int wScreen, hScreen, xScreen, yScreen, xNew, yNew; BOOL bResult; // Get the Height and Width of the child window GetWindowRect (hwndChild, &rChild); wChild = rChild.right - rChild.left; hChild = rChild.bottom - rChild.top; // Get the Height and Width of the parent window GetWindowRect (hwndParent, &rParent); wParent = rParent.right - rParent.left; hParent = rParent.bottom - rParent.top; // Get the limits of the 'workarea' #if !defined(SPI_GETWORKAREA) #define SPI_GETWORKAREA 48 #endif bResult = SystemParametersInfo( SPI_GETWORKAREA, // system parameter to query or set sizeof(RECT), // depends on action to be taken &rWorkArea, // depends on action to be taken 0); wScreen = rWorkArea.right - rWorkArea.left; hScreen = rWorkArea.bottom - rWorkArea.top; xScreen = rWorkArea.left; yScreen = rWorkArea.top; // On Windows NT, the above metrics aren't valid (yet), so they all return // '0'. Lets deal with that situation properly: if (wScreen==0 && hScreen==0) { wScreen = GetSystemMetrics(SM_CXSCREEN); hScreen = GetSystemMetrics(SM_CYSCREEN); xScreen = 0; // These values should already be '0', but just in case yScreen = 0; } // Calculate new X position, then adjust for screen xNew = rParent.left + ((wParent - wChild) /2); if (xNew < xScreen) { xNew = xScreen; } else if ((xNew+wChild) > wScreen) { xNew = (xScreen + wScreen) - wChild; } // Calculate new Y position, then adjust for screen yNew = rParent.top + ((hParent - hChild) /2); if (yNew < yScreen) { yNew = yScreen; } else if ((yNew+hChild) > hScreen) { yNew = (yScreen + hScreen) - hChild; } // Set it, and return return SetWindowPos (hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } int OnInitDialog(HWND hDlg) { HWND hListBox; DWORD dwRemoved = 0; DWORD dwTotal = 0; CenterWindow (hDlg, GetDesktopWindow ()); hListBox = GetDlgItem(hDlg, IDC_LIST); // Populate list box with Cache Container list CacheContainer(&dwTotal, &dwRemoved, CACHE_ACTION_FILL_LB, hListBox); // #57353 - after adding don't show UI if already installed // we forgot to account for /uninstall on cmd line if (g_fRemove) PostMessage(hDlg, WM_COMMAND, IDM_UNINSTALL, 0L); return FALSE; } /************************************************************************\ * FUNCTION: LoadWininet() * * If IE4 or greater version of WININET then load it up and establish * function pointers to use in rest of application. * * returns BOOL * TRUE - Sufficient version of WININET.DLL is available * FALSE - WININET.DLL is not new enough for our purposes * \************************************************************************/ BOOL LoadWininet() { HINSTANCE hDll; hDll = LoadLibrary("WININET.DLL"); if (hDll != NULL) { lpfnCreateUrlCacheContainer = (LPFNCREATEURLCACHECONTAINER)GetProcAddress(hDll, "CreateUrlCacheContainerA"); lpfnDeleteUrlCacheContainer = (LPFNDELETEURLCACHECONTAINER)GetProcAddress(hDll, "DeleteUrlCacheContainerA"); lpfnFindFirstUrlCacheContainer = (LPFNFINDFIRSTURLCACHECONTAINER)GetProcAddress(hDll, "FindFirstUrlCacheContainerA"); lpfnFindNextUrlCacheContainer = (LPFNFINDNEXTURLCACHECONTAINER)GetProcAddress(hDll, "FindNextUrlCacheContainerA"); lpfnFindCloseUrlCache = (LPFNFINDCLOSEURLCACHE)GetProcAddress(hDll, "FindCloseUrlCache"); lpfnGetUrlCacheConfigInfo = (LPFNGETURLCACHECONFIGINFO)GetProcAddress(hDll, "GetUrlCacheConfigInfoA"); if ( (!lpfnCreateUrlCacheContainer) || (!lpfnDeleteUrlCacheContainer) || (!lpfnFindFirstUrlCacheContainer) || (!lpfnFindNextUrlCacheContainer) || (!lpfnFindCloseUrlCache) || (!lpfnGetUrlCacheConfigInfo) ) { lpfnCreateUrlCacheContainer = NULL; lpfnDeleteUrlCacheContainer = NULL; lpfnFindFirstUrlCacheContainer = NULL; lpfnFindNextUrlCacheContainer = NULL; lpfnFindCloseUrlCache = NULL; lpfnGetUrlCacheConfigInfo = NULL; FreeLibrary(hDll); return FALSE; } } else return FALSE; return TRUE; } /************************************************************************\ * FUNCTION: WininetLoaded() * * returns BOOL * TRUE - Sufficient version of WININET.DLL is available * FALSE - WININET.DLL is not new enough for our purposes * \************************************************************************/ BOOL WininetLoaded() { if (lpfnCreateUrlCacheContainer) return TRUE; return FALSE; } /************************************************************************\ * FUNCTION: UrlCacheContainerExists() * * * returns BOOL * TRUE - This cache container is already installed and PrefixMap * location is correct * FALSE - Cache container is not installed or it's PrefixMap * location is different * \************************************************************************/ BOOL UrlCacheContainerExists(LPCSTR lpszUniqueVendorName, LPCSTR lpszCachePrefix, LPCSTR lpszPrefixMap) { BYTE bBuf[4096]; LPINTERNET_CACHE_CONTAINER_INFO lpCCI = (LPINTERNET_CACHE_CONTAINER_INFO) bBuf; DWORD cbCEI = sizeof(bBuf); DWORD dwModified = 0; HANDLE hEnum = NULL; BOOL bFound = FALSE; BOOL bReturn = FALSE; if (!WininetLoaded()) return FALSE; // Look for our cache container, then determine if it already exists // also need to make sure PrefixMap entry is correct // for situation when CD is placed into a different drive // after it's already been installed hEnum = lpfnFindFirstUrlCacheContainer(&dwModified, lpCCI, &cbCEI, 0); if (0 == lstrcmpi(lpszUniqueVendorName, lpCCI->lpszName)) bFound = TRUE; else { while (hEnum && lpfnFindNextUrlCacheContainer(hEnum, lpCCI, &cbCEI)) { if (0 == lstrcmpi(lpszUniqueVendorName, lpCCI->lpszName)) { bFound = TRUE; break; } } } if (bFound) { // Now check if URL CachePrefix pattern is the same if (0 == lstrcmpi(lpszCachePrefix, lpCCI->lpszCachePrefix)) { char lpBuffer[256]; DWORD cbBuffer = sizeof(lpBuffer); // Now check if PrefixMap entry is OK GetPrefixMapEntry(lpszUniqueVendorName, lpBuffer, cbBuffer); if (0 == lstrcmpi(lpBuffer, lpszPrefixMap)) bReturn = TRUE; else bReturn = FALSE; // If both CachePrefix and PrefixMap match // then we consider this entry to already exist // and is correctly installed. } } if (hEnum) lpfnFindCloseUrlCache(hEnum); return bReturn; } /************************************************************************\ * FUNCTION: _CreateUrlCacheContainer() * * Wrapper around WININET CreateUrlCacheContainer() * * Parameters: * * REMOVED * lpszUserLocalCachePath * Don't need to pass it in since can figure it out * using GetUrlCacheConfigInfo() * * ADDED * lpszPrefixMap Param added to wrapper, is missing from WININET f() * Specifies the location root path of the data * provided by the cache container. * * Workaround #1 - Pre-poplulate registry with PrefixMap * ----------------------------------------------------- * In order to work properly must pre-populate registry * with the PrefixMap entry. Otherwise WININET CreateUrlCacheContainer() * will not install the cache container. * * STEP #1: * ======== * Must setup registry entry in * HKCU\Software\Microsoft\Windows\CurrentVersion\ * Internet Settings\Cache\Extensible Cache * * For PrefixMap * Key = * PrefixMap = * * * Other Entries include: * CacheLimit = * CacheOptions = * CachePath = * CachePrefix = * These should be put there by the call to CreateUrlCacheContainer() * * STEP #2 * ======= * Call CreateUrlCacheContainer() * * Locates all the 'workarounds' to one function. \************************************************************************/ BOOL _CreateUrlCacheContainer( IN LPCSTR lpszUniqueVendorName, IN LPCSTR lpszCachePrefix, IN LPCSTR lpszPrefixMap, // New - part of WRAPPER IN LPCSTR lpszVolumeTitle, // New - part of WRAPPER IN LPCSTR lpszVolumeLabel, // New - part of WRAPPER IN DWORD KBCacheLimit, IN DWORD dwContainerType, // Not used by WININET currently IN DWORD dwOptions ) { // Enough size to get our info first time without having to realloc BYTE bBuf[4096]; LPINTERNET_CACHE_CONFIG_INFO lpCCI = (LPINTERNET_CACHE_CONFIG_INFO) bBuf; DWORD cbCEI = sizeof(bBuf); DWORD dwError = 0; char szCachePath[MAX_PATH]; DWORD dwResult = ERROR_SUCCESS; if (!WininetLoaded()) return FALSE; // Figure out local user cache location directory if (!lpfnGetUrlCacheConfigInfo(lpCCI, &cbCEI, CACHE_CONFIG_CONTENT_PATHS_FC)) { // Look for ERROR_INSUFFICIENT_BUFFER and allocate enough if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { // BUGBUG: TODO: Handle insufficient buffer case // Try again using required size returned in cbCEI //lpCCI = new INTERNET_CACHE_CONFIG_INFO[cbCEI]; } else dwError = GetLastError(); } else { if (lpCCI->dwNumCachePaths > 0) lstrcpy(szCachePath, lpCCI->CachePaths[0].CachePath); } // Add Cache Container Unique Vendor Name to CachePath // All container content will be stored in this location if(lstrlen(szCachePath) + lstrlen(lpszUniqueVendorName) >= sizeof(szCachePath) / sizeof(szCachePath[0])) { return FALSE; } lstrcat(szCachePath, lpszUniqueVendorName); // Manually put PrefixMap into Registry // HKCU\Software\Microsoft\Windows\CurrentVersion\ // Internet Settings\Cache\Extensible Cache CreateAdditionalEntries(lpszUniqueVendorName, lpszVolumeTitle, lpszVolumeLabel, lpszPrefixMap); // BUGBUG: Currently CreateUrlCacheContainer() fails if the entry // already exists. The returned GetLastError() is ERROR_INVALID_PARAM // Need to workaround this for now by enumerating the existing // cache containers and if found remove it and then re-add it. if (!lpfnCreateUrlCacheContainer(lpszUniqueVendorName, lpszCachePrefix, szCachePath, KBCacheLimit, dwContainerType, dwOptions, NULL, 0)) { BYTE bBuf[4096]; LPINTERNET_CACHE_CONTAINER_INFO lpCCI = (LPINTERNET_CACHE_CONTAINER_INFO) bBuf; DWORD cbCEI = sizeof(bBuf); DWORD dwModified = 0; HANDLE hEnum = NULL; int nCount = 0; // Assume we failed because cache container already exists // Look for our cache container, delete it, and re-create it hEnum = lpfnFindFirstUrlCacheContainer(&dwModified, lpCCI, &cbCEI, 0); if (0 == lstrcmpi(lpszUniqueVendorName, lpCCI->lpszName)) { // BUGBUG: Need to specify any options? if (!lpfnDeleteUrlCacheContainer(lpszUniqueVendorName, 0)) { dwResult = GetLastError(); } else { CreateAdditionalEntries(lpszUniqueVendorName, lpszVolumeTitle, lpszVolumeLabel, lpszPrefixMap); if (!lpfnCreateUrlCacheContainer(lpszUniqueVendorName, lpszCachePrefix, szCachePath, KBCacheLimit, dwContainerType, dwOptions, NULL, 0)) { dwResult = GetLastError(); } } } else { while (hEnum && lpfnFindNextUrlCacheContainer(hEnum, lpCCI, &cbCEI)) { if (0 == lstrcmpi(lpszUniqueVendorName, lpCCI->lpszName)) { if (!lpfnDeleteUrlCacheContainer(lpszUniqueVendorName, 0)) { dwResult = GetLastError(); } else { CreateAdditionalEntries(lpszUniqueVendorName, lpszVolumeTitle, lpszVolumeLabel, lpszPrefixMap); if (!lpfnCreateUrlCacheContainer(lpszUniqueVendorName, lpszCachePrefix, szCachePath, KBCacheLimit, dwContainerType, dwOptions, NULL, 0)) { dwResult = GetLastError(); } break; } } nCount++; } } if (hEnum) lpfnFindCloseUrlCache(hEnum); } if (dwResult != ERROR_SUCCESS) return (FALSE); else return (TRUE); // return lpfnCreateUrlCacheContainer(lpszUniqueVendorName, lpszCachePrefix, // szCachePath, KBCacheLimit, dwContainerType, // dwOptions, NULL, 0); } /************************************************************************\ * FUNCTION: CreateAdditionalEntries() * * Add the PrefixMap registry entry to the correct location in the * registry. A requirement to workaround this param missing from * the CreateUrlCacheContainer() WININET API. * \************************************************************************/ DWORD CreateAdditionalEntries(LPCSTR lpszUniqueVendorName, LPCSTR lpszVolumeTitle, LPCSTR lpszVolumeLabel, LPCSTR lpszPrefixMap) { const static char *szKeyPrefixMap = "PrefixMap"; const static char *szKeyVolumeLabel = "VolumeLabel"; const static char *szKeyVolumeTitle = "VolumeTitle"; const static char *szExtCacheRoot = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Extensible Cache"; HKEY hKeyRoot = HKEY_CURRENT_USER; // default to current user HKEY hKeyCacheExt = 0; HKEY hKeyVendor = 0; DWORD dwDisposition = 0; DWORD dwResult = ERROR_SUCCESS; CHAR szCurDir[MAX_PATH]; CHAR szVolumeLabel[MAX_PATH]; // Manually put PrefixMap into Registry // // BUGBUG: cache containers are per user if user profiles are enabled // so on NT they are always per user, on Win95 however // Need to use HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE below // depending on what's enabled. // // Hack on top of a Hack for Win95 ONLY // Since this entire function is to workaround the lack of a param // for PrefixMap in CreateUrlCacheContainer() another hack shouldn't // matter since it's only temporary // On Win95 need to check this entry // HKEY_LOCAL_MACHINE\Network\Logon // UserProfiles=DWORD:00000001 // which says if UserProfiles are turned on // If they are turned on we use HKEY_CURRENT_USER // otherwise use HKEY_LOCAL_MACHINE OSVERSIONINFO osvInfo; memset(&osvInfo, 0, sizeof(osvInfo)); osvInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osvInfo)) { if (VER_PLATFORM_WIN32_WINDOWS == osvInfo.dwPlatformId) { // We're running on Win95 so default to HKLM hKeyRoot = HKEY_LOCAL_MACHINE; } else hKeyRoot = HKEY_CURRENT_USER; // else assume NT and default to HKCU DWORD dwType = REG_DWORD; DWORD dwSize = sizeof(DWORD); DWORD dwUserProfiles = 0; HKEY hKeyProfiles = 0; // But now have to see if User Profiles are enabled if ((dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Network\\Logon", NULL, KEY_ALL_ACCESS, &hKeyProfiles)) == ERROR_SUCCESS) { if ((dwResult = RegQueryValueEx(hKeyProfiles, "UserProfiles", NULL, &dwType, (unsigned char *)&dwUserProfiles, &dwSize)) == ERROR_SUCCESS) { if ( (dwResult != ERROR_MORE_DATA) && (1L == dwUserProfiles) ) hKeyRoot = HKEY_CURRENT_USER; else hKeyRoot = HKEY_LOCAL_MACHINE; } } } if ( (dwResult = RegCreateKeyEx(hKeyRoot, szExtCacheRoot, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyCacheExt, &dwDisposition)) == ERROR_SUCCESS) { if ( (dwResult = RegOpenKeyEx(hKeyCacheExt, lpszUniqueVendorName, 0, KEY_ALL_ACCESS, &hKeyVendor)) != ERROR_SUCCESS) { // Key didn't exist // Let's try to create it dwResult = RegCreateKeyEx(hKeyCacheExt, lpszUniqueVendorName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyVendor, &dwDisposition); } } if (dwResult == ERROR_SUCCESS) { RegSetValueEx(hKeyVendor, szKeyPrefixMap, 0, REG_SZ, (CONST UCHAR *) lpszPrefixMap, lstrlen(lpszPrefixMap)+1); RegSetValueEx(hKeyVendor, szKeyVolumeLabel, 0, REG_SZ, (CONST UCHAR *) lpszVolumeLabel, lstrlen(lpszVolumeLabel)+1); RegSetValueEx(hKeyVendor, szKeyVolumeTitle, 0, REG_SZ, (CONST UCHAR *) lpszVolumeTitle, lstrlen(lpszVolumeTitle)+1); } return dwResult; } /************************************************************************\ * FUNCTION: GetPrefixMapEntry() * * Get the PrefixMap registry entry from the correct location in the * registry. * * Returns: PrefixMap entry in lpszPrefixMap * or NULL if no enty is found. * \************************************************************************/ DWORD GetPrefixMapEntry(LPCSTR lpszUniqueVendorName, LPSTR lpszPrefixMap, DWORD cbPrefixMap) { const static char *szKeyPrefixMap = "PrefixMap"; const static char *szExtCacheRoot = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Extensible Cache"; HKEY hKeyRoot = HKEY_CURRENT_USER; // default to current user HKEY hKeyCacheExt = 0; HKEY hKeyVendor = 0; DWORD dwDisposition = 0; unsigned long ulVal = 0; DWORD dwResult = ERROR_SUCCESS; // Manually put PrefixMap into Registry // // BUGBUG: cache containers are per user if user profiles are enabled // so on NT they are always per user, on Win95 however // Need to use HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE below // depending on what's enabled. // // Hack on top of a Hack for Win95 ONLY // Since this entire function is to workaround the lack of a param // for PrefixMap in CreateUrlCacheContainer() another hack shouldn't // matter since it's only temporary // On Win95 need to check this entry // HKEY_LOCAL_MACHINE\Network\Logon // UserProfiles=DWORD:00000001 // which says if UserProfiles are turned on // If they are turned on we use HKEY_CURRENT_USER // otherwise use HKEY_LOCAL_MACHINE OSVERSIONINFO osvInfo; memset(&osvInfo, 0, sizeof(osvInfo)); osvInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osvInfo)) { if (VER_PLATFORM_WIN32_WINDOWS == osvInfo.dwPlatformId) { // We're running on Win95 so default to HKLM hKeyRoot = HKEY_LOCAL_MACHINE; } else hKeyRoot = HKEY_CURRENT_USER; // else assume NT and default to HKCU DWORD dwType = REG_DWORD; DWORD dwSize = sizeof(DWORD); DWORD dwUserProfiles = 0; HKEY hKeyProfiles = 0; // But now have to see if User Profiles are enabled if ((dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Network\\Logon", NULL, KEY_ALL_ACCESS, &hKeyProfiles)) == ERROR_SUCCESS) { if ((dwResult = RegQueryValueEx(hKeyProfiles, "UserProfiles", NULL, &dwType, (unsigned char *)&dwUserProfiles, &dwSize)) == ERROR_SUCCESS) { if ( (dwResult != ERROR_MORE_DATA) && (1L == dwUserProfiles) ) hKeyRoot = HKEY_CURRENT_USER; else hKeyRoot = HKEY_LOCAL_MACHINE; } } } if ( (dwResult = RegCreateKeyEx(hKeyRoot, szExtCacheRoot, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyCacheExt, &dwDisposition)) == ERROR_SUCCESS) { if ( (dwResult = RegOpenKeyEx(hKeyCacheExt, lpszUniqueVendorName, 0, KEY_ALL_ACCESS, &hKeyVendor)) != ERROR_SUCCESS) { // Key didn't exist lpszPrefixMap[0] = '\0'; } else // key did exist so lets return it in lpszPrefixMap { // Vendor name must be unique so is it ok to assume uniqueness? if ( (dwResult = RegQueryValueEx(hKeyVendor, szKeyPrefixMap, 0, &ulVal, (LPBYTE) lpszPrefixMap, &cbPrefixMap )) == ERROR_SUCCESS ) { } else lpszPrefixMap[0] = '\0'; } } else lpszPrefixMap[0] = '\0'; return dwResult; } /************************************************************************\ * FUNCTION: WriteCacheContainerEntry() * * Manually write all the registry entries that WININET CreateUrlCacheContainer * would normally write. * * This f() is used when IE4 WININET is not yet installed. * \************************************************************************/ DWORD WriteCacheContainerEntry( IN LPCSTR lpszUniqueVendorName, IN LPCSTR lpszCachePrefix, IN LPCSTR lpszPrefixMap, // New - part of WRAPPER IN LPCSTR lpszVolumeTitle, // New - part of WRAPPER IN LPCSTR lpszVolumeLabel, // New - part of WRAPPER IN DWORD KBCacheLimit, IN DWORD dwContainerType, // Not used by WININET currently IN DWORD dwOptions ) { const static char *szCachePrefix = "CachePrefix"; const static char *szKeyPrefixMap = "PrefixMap"; const static char *szKeyVolumeLabel = "VolumeLabel"; const static char *szKeyVolumeTitle = "VolumeTitle"; const static char *szCacheLimit = "CacheLimit"; const static char *szCacheOptions = "CacheOptions"; const static char *szCachePath = "CachePath"; const static char *szExtCacheRoot = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Cache\\Extensible Cache"; HKEY hKeyRoot = HKEY_CURRENT_USER; // default to current user HKEY hKeyCacheExt = 0; HKEY hKeyVendor = 0; DWORD dwDisposition = 0; DWORD dwResult = ERROR_SUCCESS; CHAR lpszCachePath[MAX_PATH]; OSVERSIONINFO osvInfo; memset(&osvInfo, 0, sizeof(osvInfo)); osvInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osvInfo)) { if (VER_PLATFORM_WIN32_WINDOWS == osvInfo.dwPlatformId) { // We're running on Win95 so default to HKLM hKeyRoot = HKEY_LOCAL_MACHINE; } else hKeyRoot = HKEY_CURRENT_USER; // else assume NT and default to HKCU DWORD dwType = REG_DWORD; DWORD dwSize = sizeof(DWORD); DWORD dwUserProfiles = 0; HKEY hKeyProfiles = 0; BYTE bBuf[4096]; LPINTERNET_CACHE_CONFIG_INFO lpCCI = (LPINTERNET_CACHE_CONFIG_INFO) bBuf; DWORD cbCEI = sizeof(bBuf); if (!lpfnGetUrlCacheConfigInfo) { HINSTANCE hDll; hDll = LoadLibrary("WININET.DLL"); if (hDll != NULL) { lpfnGetUrlCacheConfigInfo = (LPFNGETURLCACHECONFIGINFO)GetProcAddress(hDll, "GetUrlCacheConfigInfoA"); if (!lpfnGetUrlCacheConfigInfo) { FreeLibrary(hDll); dwResult = -1; // Indicate failure } } } if (lpfnGetUrlCacheConfigInfo) { // Figure out local user cache location directory // Note: Need to use IE3 backward compatible flag // IE3: CACHE_CONFIG_DISK_CACHE_PATHS_FC // IE4: CACHE_CONFIG_CONTENT_PATHS_FC if (lpfnGetUrlCacheConfigInfo(lpCCI, &cbCEI, CACHE_CONFIG_DISK_CACHE_PATHS_FC)) { // Now need to parse the returned CachePath to remove trailing 'cache1\' // "c:\windows\Temporary Internet Files\cache1\" // look for backslash starting from end of string int i = lstrlen(lpCCI->CachePaths[0].CachePath); while( (lpCCI->CachePaths[0].CachePath[i] != '\\') && (i >= 0) ) i--; if (lpCCI->CachePaths[0].CachePath[i] == '\\') lpCCI->CachePaths[0].CachePath[i+1] = '\0'; // Leave '\' intact for later strcat if (lpCCI->dwNumCachePaths > 0) lstrcpy(lpszCachePath, lpCCI->CachePaths[0].CachePath); // Add Cache Container Unique Vendor Name to CachePath // All container content will be stored in this location if(lstrlen(lpszCachePath) + lstrlen(lpszUniqueVendorName) >= sizeof(lpszCachePath) / sizeof(lpszCachePath[0])) { return FALSE; } lstrcat(lpszCachePath, lpszUniqueVendorName); } } else { // No IE3 or IE4 WININET present // so synthesize CachePath from GetWinDir() + "Temporary Internet Files" if ( GetWindowsDirectory(lpszCachePath, MAX_PATH) > 0) { if ('\\' == lpszCachePath[lstrlen(lpszCachePath)-1]) lstrcat(lpszCachePath, _T("Temporary Internet Files")); else { lstrcat(lpszCachePath, _T("\\")); lstrcat(lpszCachePath, _T("Temporary Internet Files")); } } } // But now have to see if User Profiles are enabled if ((dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Network\\Logon", NULL, KEY_ALL_ACCESS, &hKeyProfiles)) == ERROR_SUCCESS) { if ((dwResult = RegQueryValueEx(hKeyProfiles, "UserProfiles", NULL, &dwType, (unsigned char *)&dwUserProfiles, &dwSize)) == ERROR_SUCCESS) { if ( (dwResult != ERROR_MORE_DATA) && (1L == dwUserProfiles) ) hKeyRoot = HKEY_CURRENT_USER; else hKeyRoot = HKEY_LOCAL_MACHINE; } } } if ( (dwResult = RegCreateKeyEx(hKeyRoot, szExtCacheRoot, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyCacheExt, &dwDisposition)) == ERROR_SUCCESS) { if ( (dwResult = RegOpenKeyEx(hKeyCacheExt, lpszUniqueVendorName, 0, KEY_ALL_ACCESS, &hKeyVendor)) != ERROR_SUCCESS) { // Key didn't exist // Let's try to create it dwResult = RegCreateKeyEx(hKeyCacheExt, lpszUniqueVendorName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyVendor, &dwDisposition); } } if (dwResult == ERROR_SUCCESS) { RegSetValueEx(hKeyVendor, szKeyPrefixMap, 0, REG_SZ, (CONST UCHAR *) lpszPrefixMap, lstrlen(lpszPrefixMap)+1); RegSetValueEx(hKeyVendor, szKeyVolumeLabel, 0, REG_SZ, (CONST UCHAR *) lpszVolumeLabel, lstrlen(lpszVolumeLabel)+1); RegSetValueEx(hKeyVendor, szKeyVolumeTitle, 0, REG_SZ, (CONST UCHAR *) lpszVolumeTitle, lstrlen(lpszVolumeTitle)+1); RegSetValueEx(hKeyVendor, szCachePrefix, 0, REG_SZ, (CONST UCHAR *) lpszCachePrefix, lstrlen(lpszCachePrefix)+1); RegSetValueEx(hKeyVendor, szCachePath, 0, REG_SZ, (CONST UCHAR *) lpszCachePath, lstrlen(lpszCachePath)+1); RegSetValueEx(hKeyVendor, szCacheLimit, 0, REG_DWORD, (unsigned char *)&KBCacheLimit, sizeof(DWORD)); RegSetValueEx(hKeyVendor, szCacheOptions, 0, REG_DWORD, (unsigned char *)&dwOptions, sizeof(DWORD)); } if (dwResult != ERROR_SUCCESS) return (FALSE); else return (TRUE); } /************************************************************************\ * FUNCTION: CacheContainer() * * Parameters: * dwAction - flag indicating what to do * CACHE_ACTION_INSTALL * CACHE_ACTION_REMOVE * CACHE_ACTION_FILL_LB * * hListBox - HWND to ListBox to fill in with Container names * * * Note: * if dwAction == CACHE_ACTION_FILL_LB then if hListBox * is NULL then return TRUE if ALL Containers installed * correctly or FALSE if not * * Additionally create a CDCACHE.INF at the root of the CD-ROM. * Typical contents: * * [Add.CacheContainer] * = * Encarta 97=EncartaCD * * [INF Section Name] * VolumeLabel= * VolumeTitle= * CachePrefix= * CacheRoot= * KBCacheLimit= * AutoDelete=Yes|No (default) * IncludeSubDirs=Yes|No (default) * NoDesktopInit=Yes|No (default) * * [EncartaCD] * VolumeLabel=MSENCART97 * VolumeTitle=Microsoft Encarta CD 97 * CachePrefix=http://www.microsoft.com/encarta * CacheRoot=%EXE_ROOT%\data\http * KBCacheLimit=500 * AutoDelete=Yes * IncludeSubDirs=Yes * * NOTE: %EXE_ROOT% is a replaceable param that gets set to the * path this EXE was ran from, such as E: or E:\BIN * * * Calls _CreateUrlCacheContainer() \************************************************************************/ BOOL CacheContainer(DWORD *dwTotal, DWORD *dwInstalled, DWORD dwAction, HWND hListBox) { BOOL bRet = FALSE; BOOL bVolumeLabel = FALSE; DWORD dwRes = 0; HRESULT hr = 0; int nSectionSize = 4096; // Limit each INF section to 4K char szSections[4096]; char *lpSections = (char *)szSections; const static char *szAddCacheContainerSection = "Add.CacheContainer"; const static char *szKey_Name = "Name"; const static char *szKey_VolumeTitle = "VolumeTitle"; const static char *szKey_Prefix = "CachePrefix"; const static char *szKey_Root = "CacheRoot"; const static char *szKey_CacheLimit = "KBCacheLimit"; const static char *szKey_AutoDelete = "AutoDelete"; const static char *szKey_IncludeSubDirs = "IncludeSubDirs"; const static char *szKey_NoDesktopInit = "NoDesktopInit"; char szDefault[12] = "*Unknown*"; // note: buffer needs to hold larger strings DWORD len; char szInf[STRING_BUFFER_SIZE]; char szInfPath[MAX_PATH]; char szContainerName[STRING_BUFFER_SIZE]; char szCachePrefix[STRING_BUFFER_SIZE]; char szCacheRoot[MAX_PATH]; char szPrefixMap[MAX_PATH]; char szVolumeLabel[MAX_PATH]; char szMapDrive[4]; char szVolumeTitle[MAX_PATH]; char szAutoDelete[STRING_BUFFER_SIZE]; char szIncludeSubDirs[STRING_BUFFER_SIZE]; char szNoDesktopInit[STRING_BUFFER_SIZE]; int nDefault = 0; int nCacheLimit = 0; BOOL bResult; HANDLE hFile; #define SIZE_CMD_LINE 2048 char szBuf[SIZE_CMD_LINE]; // enough for commandline // BEGIN NOTE: add vars and values in matching order // add a var by adding a new define VAR_NEW_VAR = NUM_VARS++ const char *szVars[] = { #define VAR_EXE_ROOT 0 // Replace with drive+path (ex. "D:" or "D:\PATH") of this EXE "%EXE_ROOT%", #define VAR_EXE_DRIVE 1 // Replace with drive (ex. "D:") of this EXE "%EXE_DRIVE%", #define NUM_VARS 2 "" }; int nValBuffSize = MAX_PATH; char lpValBuffer[MAX_PATH]; int nDriveBuffSize = MAX_PATH; char lpDriveBuffer[MAX_PATH]; const char *szValues[NUM_VARS + 1]; szValues[VAR_EXE_ROOT] = GetINFDir(lpValBuffer, nValBuffSize); szValues[VAR_EXE_DRIVE] = GetINFDrive(lpDriveBuffer, nDriveBuffSize); szValues[NUM_VARS] = NULL; // END NOTE: add vars and values in matching order CWaitCursor wait; // Look for INF // LoadString (g_hInst, ID_INFNAME, szInf, sizeof(szInf)); lstrcpy(szInfPath, GetINFDir(szInfPath, sizeof(szInfPath)) ); strcat (szInfPath, "\\"); strcat (szInfPath, szInf); strcat (szInfPath, ".INF"); hFile = CreateFile(szInfPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFile) { CloseHandle(hFile); hFile = NULL; // Is there a [Add.CacheContainer] section // BUGBUG: GetPrivateProfileSection() fails on Win95 // Workaround for GetPrivateProfileSection() failure on Win95 szDefault[0] = '\0'; len = GetPrivateProfileString(szAddCacheContainerSection, NULL, szDefault, lpSections, nSectionSize, szInfPath); if (!len) { // no CD-ROM Cache Container sections in INF // BUGBUG: Display a message if in NON Silent mode? // This is case where AUTORUN.INF has no [Add.Container] section } else { // lpBuffer now has list of key strings (as in key=value) // final pair terminated with extra NULL // // Loop through each cache container entry while (*lpSections) { WORD dResult = 0; // Init flags for this container to map-able. DWORD dwOptions = INTERNET_CACHE_CONTAINER_MAP_ENABLED; GetPrivateProfileString(szAddCacheContainerSection, lpSections, szDefault, szContainerName, STRING_BUFFER_SIZE, szInfPath); if (szContainerName) { (*dwTotal)++; // Keep track of how many cache containers in INF // Build PrefixMap // // BUGBUG: Default to root? lstrcpy(szDefault, "%EXE_ROOT%"); // Get the PrefixMap entry dwRes = GetPrivateProfileString(szContainerName, szKey_Root, szDefault, szCacheRoot, MAX_PATH, szInfPath); // Replace any %parameters% // S_OK indicates that something was expanded if (S_OK == (hr = ExpandEntry(szCacheRoot, szBuf, SIZE_CMD_LINE, szVars, szValues))) lstrcpyn(szPrefixMap, szBuf, sizeof(szPrefixMap)); else lstrcpy(szPrefixMap, szCacheRoot); memcpy(szMapDrive, szPrefixMap, 2); memcpy(szMapDrive + 2, "\\", sizeof("\\")); if (GetVolumeInformation(szMapDrive, szVolumeLabel, MAX_PATH, NULL, NULL, NULL, NULL, 0)) { bVolumeLabel = TRUE; } else { *szVolumeLabel = '\0'; bVolumeLabel = FALSE; } lstrcpy(szDefault, ""); GetPrivateProfileString(szContainerName, szKey_Prefix, szDefault, szCachePrefix, STRING_BUFFER_SIZE, szInfPath); lstrcpy(szDefault, ""); GetPrivateProfileString(szContainerName, szKey_VolumeTitle, szDefault, szVolumeTitle, STRING_BUFFER_SIZE, szInfPath); // Now trim off trailing backslash '\' from szCachePrefix // workaround for #43375 int i = lstrlen(szCachePrefix); if (i > 0) if ('\\' == szCachePrefix[i - 1]) szCachePrefix[i - 1] = '\0'; // BUGBUG: Should create custom Profile f() to // read/return DWORD value rather than int nDefault = 500; // 500K Cache Limit nCacheLimit = GetPrivateProfileInt(szContainerName, szKey_CacheLimit, nDefault, szInfPath); dResult = GetProfileBooleanWord(szContainerName, szKey_AutoDelete, szInfPath); switch (dResult) { case -1: // The key did not exist in INF break; // default is No/False for AutoDelete case FALSE: break; case TRUE: dwOptions |= INTERNET_CACHE_CONTAINER_AUTODELETE; break; } dResult = GetProfileBooleanWord(szContainerName, szKey_IncludeSubDirs, szInfPath); switch (dResult) { case -1: // The key did not exist in INF break; // default is Yes/True for IncludeSubDirs case FALSE: dwOptions |= INTERNET_CACHE_CONTAINER_NOSUBDIRS; // Don't include subdirs in cacheview break; case TRUE: break; } dResult = GetProfileBooleanWord(szContainerName, szKey_NoDesktopInit, szInfPath); switch (dResult) { case -1: // The key did not exist in INF break; // default is No/False for NoDesktopInit case FALSE: break; case TRUE: dwOptions |= INTERNET_CACHE_CONTAINER_NODESKTOPINIT; break; } switch (dwAction) { case CACHE_ACTION_INSTALL: // Call CreateUrlCacheContainer WRAPPER if (bVolumeLabel) { bRet = _CreateUrlCacheContainer(lpSections, szCachePrefix, szPrefixMap, szVolumeTitle, szVolumeLabel, nCacheLimit, 0, dwOptions); } else { bRet = FALSE; } break; case CACHE_ACTION_REMOVE: if (!WininetLoaded()) return FALSE; bRet = lpfnDeleteUrlCacheContainer(lpSections, dwOptions); break; case CACHE_ACTION_FILL_LB: // Fill listbox hListBox if (hListBox) { SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)lpSections); } else { // hListBox is NULL // // if dwAction == CACHE_ACTION_FILL_LB then if hListBox // is NULL then return TRUE if ALL Containers installed // correctly or FALSE if not // if (UrlCacheContainerExists(lpSections, szCachePrefix, szPrefixMap)) bRet = TRUE; else return FALSE; // One container is not installed so bail out } break; case CACHE_ACTION_MAKE_REG_ENTRIES: if (bVolumeLabel) { bRet = WriteCacheContainerEntry(lpSections, szCachePrefix, szPrefixMap, szVolumeTitle, szVolumeLabel, nCacheLimit, 0, dwOptions); } else bRet = FALSE; break; } if (bRet) (*dwInstalled)++; // Keep track of successful installs } //else empty section entry, ignore and move to next // Get Next Section name while ( (*(lpSections++) != '\0') ); } } } else { // Couldn't find INF file // BUGBUG: need to do anything else here? } return bRet; } /************************************************************************\ * FUNCTION: ExpandEntry() * * Borrowed from urlmon\download\hooks.cxx \************************************************************************/ HRESULT ExpandEntry( LPSTR szSrc, LPSTR szBuf, DWORD cbBuffer, const char * szVars[], const char * szValues[]) { //Assert(szSrc); HRESULT hr = S_FALSE; LPSTR pchSrc = szSrc; // start parsing at begining of cmdline LPSTR pchOut = szBuf; // set at begin of out buffer DWORD cbLen = 0; while (*pchSrc) { // look for match of any of our env vars if (*pchSrc == '%') { HRESULT hr1 = ExpandVar(pchSrc, pchOut, cbLen, // all passed by ref! cbBuffer, szVars, szValues); if (FAILED(hr1)) { hr = hr1; goto Exit; } if (hr1 == S_OK) { // expand var expanded this hr = hr1; continue; } } // copy till the next % or nul if ((cbLen + 1) < cbBuffer) { *pchOut++ = *pchSrc++; cbLen++; } else { // out of buffer space *pchOut = '\0'; // term hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); goto Exit; } } *pchOut = '\0'; // term Exit: return hr; } /************************************************************************\ * FUNCTION: ExpandVar() * * Borrowed from urlmon\download\hooks.cxx \************************************************************************/ HRESULT ExpandVar( LPSTR& pchSrc, // passed by ref! LPSTR& pchOut, // passed by ref! DWORD& cbLen, // passed by ref! DWORD cbBuffer, const char * szVars[], const char * szValues[]) { HRESULT hr = S_FALSE; int cbvar = 0; //Assert (*pchSrc == '%'); for (int i=0; szVars[i] && (cbvar = lstrlen(szVars[i])) ; i++) { // for each variable int cbneed = 0; if ( (szValues[i] == NULL) || !(cbneed = lstrlen(szValues[i]))) continue; cbneed++; // add for nul if (0 == strncmp(szVars[i], pchSrc, cbvar)) { // found something we can expand if ((cbLen + cbneed) >= cbBuffer) { // out of buffer space *pchOut = '\0'; // term hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); goto Exit; } lstrcpy(pchOut, szValues[i]); cbLen += (cbneed -1); //don't count the nul pchSrc += cbvar; // skip past the var in pchSrc pchOut += (cbneed -1); // skip past dir in pchOut hr = S_OK; goto Exit; } } Exit: return hr; } // Return drive+path without trailing backslash LPSTR GetINFDir(LPSTR lpBuffer, int nBuffSize) { // Figure out what directory we've been started in GetModuleFileName(g_hInst, lpBuffer, nBuffSize); // Now trim off trailing backslash '\' if any int i = lstrlen(lpBuffer); if (i > 0) if ('\\' == lpBuffer[i - 1]) lpBuffer[i - 1] = '\0'; // Get rid of executable name i = lstrlen(lpBuffer); while( (lpBuffer[i] != '\\') && (i >= 0) ) i--; if (lpBuffer[i] == '\\') lpBuffer[i] = '\0'; return lpBuffer; } // Return drive without trailing backslash LPSTR GetINFDrive(LPSTR lpBuffer, int nBuffSize) { // Figure out what directory we've been started in GetModuleFileName(g_hInst, lpBuffer, nBuffSize); if (!lpBuffer) return NULL; LPSTR lpSaveBuffer = lpBuffer; // Now trim off everything after first colon ':' if (':' == lpBuffer[1]) lpBuffer[2] = '\0'; else { // assumption that lpBuffer of form "D:\path" failed // so actually parse it // #48022 robgil - add check for end of lpBuffer string while (*lpBuffer != '\0' && *lpBuffer != ':') lpBuffer++; if (':' == *lpBuffer) *(lpBuffer + 1) = '\0'; else { // #48022 // Need to return \\server\share // for Drive when a UNC path lpBuffer = lpSaveBuffer; if ('\\' == lpBuffer[0] && '\\' == lpBuffer[1]) { lpBuffer += 2; // move past leading '\\' while (*lpBuffer != '\0' && *lpBuffer != '\\') lpBuffer++; if ('\\' == *lpBuffer) { lpBuffer++; while (*lpBuffer != '\0' && *lpBuffer != '\\') lpBuffer++; if ('\\' == *lpBuffer) *lpBuffer = '\0'; } } } } return lpSaveBuffer; } //------------------------------------------------------------------------ // BOOL GetProfileBooleanWord // // Description: // Retrieves the value associated with szKeyName and // evaluates to a TRUE or FALSE. If a value is not // associated with the key, -1 is returned. // // Parameters: // LPSTR szKeyName // pointer to key name // // Return Value: // WORD // -1, if a setting for the given key does not exist // TRUE, if value evaluates to a "positive" or "true" // FALSE, otherwise // //------------------------------------------------------------------------ WORD GetProfileBooleanWord ( LPCTSTR szIniSection, LPCTSTR szKeyName, LPCTSTR szIniFile ) { TCHAR szTemp[10]; GetPrivateProfileString( szIniSection, szKeyName, _T(""), szTemp, sizeof( szTemp ), szIniFile ) ; if (0 == lstrlen( szTemp )) return ( (WORD) -1 ) ; if ((0 == lstrcmpi( szTemp, gszIniValTrue )) || (0 == lstrcmpi( szTemp, gszIniValYes )) || (0 == lstrcmpi( szTemp, gszIniValOn ))) return ( TRUE ) ; // Try and convert something numeric if (0 != _ttoi(szTemp)) // atoi (via tchar.h) return ( TRUE ); return ( FALSE ) ; } // end of GetProfileBooleanWord()