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
1840 lines
55 KiB
/******************************************************************************\
|
|
*
|
|
* 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]
|
|
* <Friendly Unique Vendor Name>=<INF Section Name>
|
|
*
|
|
* [INF Section Name]
|
|
* CachePrefix=<string>
|
|
* CacheRoot=<relative path on CD-ROM of data>
|
|
* KBCacheLimit=<numerical amount in KB>
|
|
* 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 = <Unique Vendor Name>
|
|
* PrefixMap = <string>
|
|
*
|
|
*
|
|
* Other Entries include:
|
|
* CacheLimit = <DWORD>
|
|
* CacheOptions = <DWORD>
|
|
* CachePath = <string>
|
|
* CachePrefix = <string>
|
|
* 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]
|
|
* <Unique Vendor Name>=<INF Section Name>
|
|
* Encarta 97=EncartaCD
|
|
*
|
|
* [INF Section Name]
|
|
* VolumeLabel=<string>
|
|
* VolumeTitle=<string>
|
|
* CachePrefix=<string>
|
|
* CacheRoot=<relative path on CD-ROM of data>
|
|
* KBCacheLimit=<numerical amount in KB>
|
|
* 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()
|
|
|