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.
2295 lines
81 KiB
2295 lines
81 KiB
#include "pch.hxx"
|
|
#include <regutil.h>
|
|
#include <initguid.h>
|
|
#include <shlguid.h>
|
|
#include "util.h"
|
|
#include "strings.h"
|
|
#include "msident.h"
|
|
#include <shellapi.h>
|
|
|
|
ASSERTDATA
|
|
|
|
const LPCTSTR c_szVers[] = { c_szVERnone, c_szVER1_0, c_szVER1_1, c_szVER4_0, c_szVER5B1 };
|
|
const LPCTSTR c_szBlds[] = { c_szBLDnone, c_szBLD1_0, c_szBLD1_1, c_szBLD4_0, c_szBLD5B1 };
|
|
#ifdef SETUP_LOG
|
|
const LPTSTR c_szLOGVERS[] = {"None", "1.0", "1.1", "4.0x", "5.0B1", "5.0x", "6.0x", "Unknown"};
|
|
|
|
C_ASSERT((sizeof(c_szLOGVERS)/sizeof(c_szLOGVERS[0]) == VER_MAX+1));
|
|
|
|
#endif
|
|
|
|
|
|
#define FORCE_DEL(_sz) { \
|
|
if ((dwAttr = GetFileAttributes(_sz)) != 0xFFFFFFFF) \
|
|
{ \
|
|
SetFileAttributes(_sz, dwAttr & ~FILE_ATTRIBUTE_READONLY); \
|
|
DeleteFile(_sz); \
|
|
} }
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CreateLink
|
|
|
|
********************************************************************/
|
|
// Target Arguments File for link Description File w/ Icon Icn Index
|
|
HRESULT CreateLink(LPCTSTR lpszPathObj, LPCTSTR lpszArg, LPCTSTR lpszPathLink, LPCTSTR lpszDesc, LPCTSTR lpszIcon, int iIcon)
|
|
{
|
|
HRESULT hres;
|
|
IShellLink* psl;
|
|
|
|
Assert(lpszPathObj != NULL);
|
|
Assert(lpszPathLink != NULL);
|
|
|
|
// Get a pointer to the IShellLink interface.
|
|
hres = CoCreateInstance(CLSID_ShellLink, NULL,
|
|
CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
IPersistFile* ppf;
|
|
TCHAR szTarget[MAX_PATH];
|
|
|
|
// Use REG_EXPAND_SZ if possible
|
|
AddEnvInPath(lpszPathObj, szTarget, ARRAYSIZE(szTarget));
|
|
|
|
// Set the path to the shortcut target, and add the
|
|
// description.
|
|
if (SUCCEEDED(psl->SetPath(szTarget)) &&
|
|
(lpszArg == NULL || SUCCEEDED(psl->SetArguments(lpszArg))) &&
|
|
(NULL == lpszDesc || SUCCEEDED(psl->SetDescription(lpszDesc))) &&
|
|
(lpszIcon == NULL || SUCCEEDED(psl->SetIconLocation(lpszIcon, iIcon))))
|
|
{
|
|
// Query IShellLink for the IPersistFile interface for saving the
|
|
// shortcut in persistent storage.
|
|
hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
WORD wsz[MAX_PATH];
|
|
|
|
// Ensure that the string is ANSI.
|
|
MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH);
|
|
|
|
// Save the link by calling IPersistFile::Save.
|
|
hres = ppf->Save(wsz, TRUE);
|
|
ppf->Release();
|
|
}
|
|
}
|
|
|
|
psl->Release();
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: FRedistMode
|
|
|
|
********************************************************************/
|
|
BOOL FRedistMode()
|
|
{
|
|
HKEY hkey;
|
|
DWORD cb;
|
|
DWORD dwInstallMode=0;
|
|
|
|
static BOOL s_fRedistInit = FALSE;
|
|
static BOOL s_fRedistMode = FALSE;
|
|
|
|
if (!s_fRedistInit)
|
|
{
|
|
s_fRedistInit = TRUE;
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, si.pszVerInfo, 0, KEY_READ, &hkey))
|
|
{
|
|
cb = sizeof(dwInstallMode);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szIEInstallMode, 0, NULL, (LPBYTE)&dwInstallMode, &cb))
|
|
{
|
|
s_fRedistMode = !!(dwInstallMode);
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
|
|
return s_fRedistMode;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: SetHandlers
|
|
|
|
********************************************************************/
|
|
void SetHandlers()
|
|
{
|
|
switch (si.saApp)
|
|
{
|
|
case APP_OE:
|
|
if (!FRedistMode())
|
|
{
|
|
ISetDefaultNewsHandler(c_szMOE, DEFAULT_DONTFORCE);
|
|
ISetDefaultMailHandler(c_szMOE, DEFAULT_DONTFORCE | DEFAULT_SETUPMODE);
|
|
}
|
|
break;
|
|
|
|
case APP_WAB:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: AddWABCustomStrings
|
|
|
|
SYNOPSIS: Adds machine-specific strings to WAB inf
|
|
|
|
********************************************************************/
|
|
void AddWABCustomStrings()
|
|
{
|
|
HKEY hkey;
|
|
TCHAR szTemp[MAX_PATH];
|
|
TCHAR szINFFile[MAX_PATH];
|
|
DWORD cb;
|
|
BOOL fOK = FALSE;
|
|
|
|
// People don't want us creating a new Accessories group in our
|
|
// install language if it differs from the system language
|
|
// Soln: Advpack writes the name of the group for us, use that
|
|
|
|
// Construct INF file name from dir and filename
|
|
wnsprintf(szINFFile, ARRAYSIZE(szINFFile), c_szFileEntryFmt, si.szInfDir, si.pszInfFile);
|
|
|
|
// We want to enclose the string in quotes
|
|
szTemp[0] = '"';
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegWinCurrVer, 0, KEY_READ, &hkey))
|
|
{
|
|
cb = ARRAYSIZE(szTemp) - 1;
|
|
fOK = (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szSMAccessories, 0, NULL, (LPBYTE)&szTemp[1], &cb));
|
|
|
|
// We want cb to tell us where to put the closing quote. RegQueryValueEx includes null in length, so we'd
|
|
// normally -1, but thanks to the opening quote in [0], the string is as long as cb
|
|
//cb--;
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
if (fOK)
|
|
{
|
|
// Append closing quote
|
|
szTemp[cb++] = '"';
|
|
szTemp[cb] = 0;
|
|
|
|
// Add string to INF so per-user stub will create right link
|
|
WritePrivateProfileString(c_szStringSection, c_szAccessoriesString, szTemp, szINFFile);
|
|
}
|
|
|
|
// INF ships with a default value in case Advpack let us down
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: RunPostSetup
|
|
|
|
********************************************************************/
|
|
void RunPostSetup()
|
|
{
|
|
switch (si.saApp)
|
|
{
|
|
case APP_OE:
|
|
RegisterExes(TRUE);
|
|
break;
|
|
|
|
case APP_WAB:
|
|
AddWABCustomStrings();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: OpenDirectory
|
|
|
|
SYNOPSIS: checks for existence of directory, if it doesn't exist
|
|
it is created
|
|
|
|
********************************************************************/
|
|
HRESULT OpenDirectory(TCHAR *szDir)
|
|
{
|
|
TCHAR *sz, ch;
|
|
HRESULT hr;
|
|
|
|
Assert(szDir != NULL);
|
|
hr = S_OK;
|
|
|
|
if (!CreateDirectory(szDir, NULL) && ERROR_ALREADY_EXISTS != GetLastError())
|
|
{
|
|
Assert(szDir[1] == _T(':'));
|
|
Assert(szDir[2] == _T('\\'));
|
|
|
|
sz = &szDir[3];
|
|
|
|
while (TRUE)
|
|
{
|
|
while (*sz != 0)
|
|
{
|
|
if (!IsDBCSLeadByte(*sz))
|
|
{
|
|
if (*sz == _T('\\'))
|
|
break;
|
|
}
|
|
sz = CharNext(sz);
|
|
}
|
|
ch = *sz;
|
|
*sz = 0;
|
|
if (!CreateDirectory(szDir, NULL))
|
|
{
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
|
{
|
|
hr = E_FAIL;
|
|
*sz = ch;
|
|
break;
|
|
}
|
|
}
|
|
*sz = ch;
|
|
if (*sz == 0)
|
|
break;
|
|
sz++;
|
|
}
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
BOOL PathAddSlash(LPTSTR pszPath, DWORD *pcb)
|
|
{
|
|
Assert(pszPath && pcb);
|
|
|
|
DWORD cb = *pcb;
|
|
LPTSTR pszEnd;
|
|
|
|
*pcb = 0;
|
|
if (!cb)
|
|
cb = lstrlen(pszPath);
|
|
|
|
pszEnd = CharPrev(pszPath, pszPath+cb);
|
|
|
|
// Who knows why this is here... :-)
|
|
if (';' == *pszEnd)
|
|
{
|
|
cb--;
|
|
pszEnd--;
|
|
}
|
|
|
|
if (*pszEnd != '\\')
|
|
{
|
|
pszPath[cb++] = '\\';
|
|
pszPath[cb] = 0;
|
|
}
|
|
|
|
*pcb = cb;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL FGetSpecialFolder(int iFolder, LPTSTR pszPath)
|
|
{
|
|
BOOL fOK = FALSE;
|
|
LPITEMIDLIST pidl = NULL;
|
|
|
|
pszPath[0] = 0;
|
|
|
|
if (S_OK == SHGetSpecialFolderLocation(NULL, iFolder, &pidl) && SHGetPathFromIDList(pidl, pszPath))
|
|
fOK = TRUE;
|
|
|
|
SafeMemFree(pidl);
|
|
return fOK;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: FGetOELinkInfo
|
|
|
|
********************************************************************/
|
|
BOOL FGetOELinkInfo(OEICON iIcon, BOOL fCreate, LPTSTR pszPath, LPTSTR pszTarget, LPTSTR pszDesc, DWORD *pdwInfo)
|
|
{
|
|
BOOL fDir = FALSE;
|
|
HKEY hkey;
|
|
DWORD cb = 0;
|
|
DWORD dwType;
|
|
TCHAR szTemp[MAX_PATH];
|
|
TCHAR szRes[CCHMAX_RES];
|
|
|
|
Assert(pdwInfo);
|
|
Assert(pszPath || pszTarget || pszDesc);
|
|
|
|
*pdwInfo = 0;
|
|
|
|
ZeroMemory(szTemp, ARRAYSIZE(szTemp));
|
|
switch(iIcon)
|
|
{
|
|
|
|
// The MEMPHIS ICW erroneously creates an all-user desktop icon for OE
|
|
case ICON_ICWBAD:
|
|
|
|
// Find the location of the all-users desktop
|
|
if (FGetSpecialFolder(CSIDL_COMMON_DESKTOPDIRECTORY, pszPath))
|
|
{
|
|
fDir = TRUE;
|
|
}
|
|
// Memphis doesn't support CSIDL_COMMON_DESKTOP
|
|
else if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegFolders, 0, KEY_QUERY_VALUE, &hkey))
|
|
{
|
|
cb = MAX_PATH * sizeof(TCHAR);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szValueCommonDTop, NULL, &dwType, (LPBYTE)pszPath, &cb))
|
|
{
|
|
if (REG_EXPAND_SZ == dwType)
|
|
{
|
|
// ExpandEnvironmentStrings ret value doesn't seem to match the docs :-(
|
|
cb = ExpandEnvironmentStrings(pszPath, szTemp, ARRAYSIZE(szTemp));
|
|
if (fDir = cb != 0)
|
|
{
|
|
StrCpyN(pszPath, szTemp, MAX_PATH);
|
|
cb = lstrlen(pszPath);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fDir = TRUE;
|
|
// RegQueryValueEx includes NULL in count
|
|
cb--;
|
|
}
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
if (fDir && PathAddSlash(pszPath, &cb) && SUCCEEDED(OpenDirectory(pszPath)))
|
|
{
|
|
// 1 for a null
|
|
LoadString(g_hInstance, IDS_ATHENA, szRes, MAX_PATH - cb - 1 - c_szLinkFmt_LEN);
|
|
wnsprintf(&pszPath[cb], MAX_PATH - cb, c_szLinkFmt, szRes);
|
|
*pdwInfo |= LI_PATH;
|
|
}
|
|
break;
|
|
|
|
case ICON_QLAUNCH:
|
|
case ICON_QLAUNCH_OLD:
|
|
if (FGetSpecialFolder(CSIDL_APPDATA, pszPath))
|
|
{
|
|
fDir = TRUE;
|
|
}
|
|
else if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, c_szRegFolders, 0, NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE | KEY_READ, NULL, &hkey, &dwType))
|
|
{
|
|
cb = MAX_PATH * sizeof(TCHAR);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szValueAppData, NULL, &dwType, (LPBYTE)pszPath, &cb))
|
|
{
|
|
if (REG_EXPAND_SZ == dwType)
|
|
{
|
|
cb = ExpandEnvironmentStrings(pszPath, szTemp, ARRAYSIZE(szTemp));
|
|
if (fDir = 0 != cb)
|
|
{
|
|
StrCpyN(pszPath, szTemp, MAX_PATH);
|
|
cb = lstrlen(pszPath);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// RegQueryValueEx includes NULL in their counts
|
|
cb--;
|
|
fDir = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StrCpyN(pszPath, si.szWinDir, MAX_PATH);
|
|
cb = lstrlen(pszPath);
|
|
cb += LoadString(g_hInstance, IDS_APPLICATION_DATA, &pszPath[cb], MAX_PATH - cb);
|
|
// + 1 for NULL
|
|
RegSetValueEx(hkey, c_szValueAppData, 0, REG_SZ, (LPBYTE)pszPath, (cb + 1) * sizeof(TCHAR));
|
|
|
|
fDir = TRUE;
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
if (fDir && PathAddSlash(pszPath, &cb))
|
|
{
|
|
StrCpyN(&pszPath[cb], c_szQuickLaunchDir, MAX_PATH - cb);
|
|
cb += c_szQuickLaunchDir_LEN;
|
|
|
|
if (SUCCEEDED(OpenDirectory(pszPath)))
|
|
{
|
|
// 5 = 1 for null + 4 for .lnk
|
|
LoadString(g_hInstance, ICON_QLAUNCH == iIcon ? IDS_LAUNCH_ATHENA : IDS_MAIL, szRes, MAX_PATH - cb - 5);
|
|
wnsprintf(&pszPath[cb], MAX_PATH - cb, c_szLinkFmt, szRes);
|
|
*pdwInfo |= LI_PATH;
|
|
|
|
// We need more details for ICON_QLAUNCH
|
|
if (ICON_QLAUNCH == iIcon && fCreate)
|
|
{
|
|
// Don't use Description because NT5 shows name and comment
|
|
//lstrcpy(pszDesc, szRes);
|
|
//*pdwInfo |= LI_DESC;
|
|
|
|
if (GetExePath(c_szMainExe, pszTarget, MAX_PATH, FALSE))
|
|
*pdwInfo |= LI_TARGET;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ICON_MAPIRECIP:
|
|
if (FGetSpecialFolder(CSIDL_SENDTO, pszPath) && PathAddSlash(pszPath, &cb) && SUCCEEDED(OpenDirectory(pszPath)))
|
|
{
|
|
// 10 = 1 for NULL + 9 for .MAPIMAIL
|
|
LoadString(g_hInstance, IDS_MAIL_RECIPIENT, szRes, MAX_PATH - cb - 10);
|
|
wnsprintf(&pszPath[cb], MAX_PATH - cb, c_szFmtMapiMailExt, szRes);
|
|
*pdwInfo |= LI_PATH;
|
|
}
|
|
break;
|
|
|
|
case ICON_DESKTOP:
|
|
if (FGetSpecialFolder(CSIDL_DESKTOP, pszPath))
|
|
fDir = TRUE;
|
|
// HACK to workaround TW Memphis: Try the registry
|
|
else if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegFolders, 0, KEY_READ, &hkey))
|
|
{
|
|
cb = MAX_PATH * sizeof(TCHAR);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szDesktop, 0, &dwType, (LPBYTE)pszPath, &cb))
|
|
{
|
|
// Handle REG_EXPAND_SZ
|
|
if (REG_EXPAND_SZ == dwType)
|
|
{
|
|
cb = ExpandEnvironmentStrings(pszPath, szTemp, ARRAYSIZE(szTemp));
|
|
if (fDir = cb != 0)
|
|
{
|
|
StrCpyN(pszPath, szTemp, MAX_PATH);
|
|
fDir = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// RegQueryValueEx includes NULL
|
|
cb--;
|
|
fDir = TRUE;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
if (fDir && PathAddSlash(pszPath, &cb) && SUCCEEDED(OpenDirectory(pszPath)))
|
|
{
|
|
// 5 = 1 for NULL + 4 for .lnk
|
|
LoadString(g_hInstance, IDS_ATHENA, szRes, MAX_PATH - cb - 5);
|
|
wnsprintf(&pszPath[cb], MAX_PATH - cb, c_szLinkFmt, szRes);
|
|
|
|
*pdwInfo |= LI_PATH;
|
|
|
|
if (fCreate)
|
|
{
|
|
// Description for Desktop link
|
|
LoadString(g_hInstance, IDS_OEDTOP_TIP, pszDesc, CCHMAX_RES);
|
|
*pdwInfo |= LI_DESC;
|
|
|
|
if (GetExePath(c_szMainExe, pszTarget, MAX_PATH, FALSE))
|
|
*pdwInfo |= LI_TARGET;
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
if (*pdwInfo)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: FProcessOEIcon
|
|
|
|
SYNOPSIS: Should we manipulate this icon?
|
|
|
|
********************************************************************/
|
|
BOOL FProcessOEIcon(OEICON iIcon, BOOL fCreate)
|
|
{
|
|
BOOL fProcess = TRUE;
|
|
|
|
switch (iIcon)
|
|
{
|
|
case ICON_ICWBAD:
|
|
// Don't delete the ICW's bad icon in redist mode or on NT5 as we won't create a replacement
|
|
if (((VER_PLATFORM_WIN32_NT == si.osv.dwPlatformId) && (si.osv.dwMajorVersion >= 5)) || FRedistMode())
|
|
{
|
|
fProcess = FALSE;
|
|
}
|
|
break;
|
|
|
|
case ICON_DESKTOP:
|
|
// Don't create the desktop icon on NT5+, Win98 OSR+ or if we are in redist mode
|
|
if (fCreate && ( ((VER_PLATFORM_WIN32_NT == si.osv.dwPlatformId) && (si.osv.dwMajorVersion >= 5)) ||
|
|
// Disabled this temporarily (through techbeta)
|
|
#if 0
|
|
((VER_PLATFORM_WIN32_WINDOWS == si.osv.dwPlatformId) &&
|
|
(((4 == si.osv.dwMajorVersion) && (10 == si.osv.dwMinorVersion) && (LOWORD(si.osv.dwBuildNumber) > 1998)) ||
|
|
((4 == si.osv.dwMajorVersion) && (si.osv.dwMinorVersion > 10)) ||
|
|
(si.osv.dwMajorVersion > 4)) ) ||
|
|
#endif
|
|
FRedistMode() ) )
|
|
fProcess = FALSE;
|
|
break;
|
|
|
|
case ICON_QLAUNCH:
|
|
case ICON_QLAUNCH_OLD:
|
|
// No Quick Launch Icon on whistler
|
|
if(fCreate &&
|
|
VER_PLATFORM_WIN32_NT == si.osv.dwPlatformId &&
|
|
(si.osv.dwMajorVersion > 5 ||
|
|
(si.osv.dwMajorVersion == 5 && si.osv.dwMinorVersion > 0)))
|
|
fProcess = FALSE;
|
|
break;
|
|
}
|
|
|
|
return fProcess;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: HandleOEIcon
|
|
|
|
SYNOPSIS: Performs actual work on Icon
|
|
|
|
********************************************************************/
|
|
void HandleOEIcon(OEICON icn, BOOL fCreate, LPTSTR pszPath, LPTSTR pszTarget, LPTSTR pszDesc)
|
|
{
|
|
DWORD dwAttr;
|
|
HANDLE hFile;
|
|
|
|
switch (icn)
|
|
{
|
|
case ICON_QLAUNCH_OLD:
|
|
case ICON_ICWBAD:
|
|
if (pszPath)
|
|
FORCE_DEL(pszPath);
|
|
break;
|
|
|
|
case ICON_QLAUNCH:
|
|
case ICON_DESKTOP:
|
|
if (pszPath)
|
|
{
|
|
FORCE_DEL(pszPath);
|
|
if (fCreate && pszTarget && !IsXPSP1OrLater())
|
|
{
|
|
CreateLink(pszTarget, NULL, pszPath, pszDesc, pszTarget, -2);
|
|
SetFileAttributes(pszPath, FILE_ATTRIBUTE_READONLY);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ICON_MAPIRECIP:
|
|
if (fCreate && pszPath)
|
|
{
|
|
hFile = CreateFile(pszPath, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle(hFile);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: HandleOELinks
|
|
|
|
********************************************************************/
|
|
void HandleOELinks(BOOL fCreate)
|
|
{
|
|
int i;
|
|
TCHAR szPath[MAX_PATH];
|
|
TCHAR szTarget[MAX_PATH];
|
|
TCHAR szDescription[CCHMAX_RES];
|
|
DWORD dwInfo;
|
|
|
|
// Process each Icon in turn
|
|
for (i = 0; i < ICON_LAST_ICON; i++)
|
|
{
|
|
if (FProcessOEIcon((OEICON)i, fCreate))
|
|
{
|
|
if(FGetOELinkInfo((OEICON)i, fCreate, szPath, szTarget, szDescription, &dwInfo))
|
|
{
|
|
HandleOEIcon((OEICON)i, fCreate,
|
|
(dwInfo & LI_PATH) ? szPath : NULL,
|
|
(dwInfo & LI_TARGET) ? szTarget : NULL,
|
|
(dwInfo & LI_DESC) ? szDescription : NULL);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: HandleLinks
|
|
|
|
********************************************************************/
|
|
void HandleLinks(BOOL fCreate)
|
|
{
|
|
switch (si.saApp)
|
|
{
|
|
case APP_OE:
|
|
HandleOELinks(fCreate);
|
|
break;
|
|
|
|
case APP_WAB:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: TranslateVers
|
|
|
|
SYNOPSIS: Takes 5.0B1 versions and translates to bld numbers
|
|
|
|
********************************************************************/
|
|
BOOL TranslateVers(SETUPVER *psv, LPTSTR pszVer, int cch)
|
|
{
|
|
BOOL fTranslated = FALSE;
|
|
*psv = VER_NONE;
|
|
|
|
// Special case builds 624-702
|
|
if (!lstrcmp(pszVer, c_szVER5B1old))
|
|
{
|
|
StrCpyN(pszVer, c_szBlds[VER_5_0_B1], cch);
|
|
*psv = VER_5_0_B1;
|
|
fTranslated = TRUE;
|
|
}
|
|
else
|
|
for (int i = VER_NONE; i < VER_5_0; i++)
|
|
if (!lstrcmp(c_szVers[i], pszVer))
|
|
{
|
|
// HACK! Special case WAB 1_0 match - it could be 1_1...
|
|
// Don't care on Win9X or NT as data is still stored in same place
|
|
if (APP_WAB == si.saApp && VER_1_0 == i && CALLER_IE == si.caller)
|
|
{
|
|
// Is Windows\WAB.exe backed up as part of OE?
|
|
TCHAR szTemp[MAX_PATH];
|
|
wnsprintf(szTemp, ARRAYSIZE(szTemp), c_szFileEntryFmt, si.szWinDir, "wab.exe");
|
|
|
|
if (OEFileBackedUp(szTemp, ARRAYSIZE(szTemp)))
|
|
i = VER_1_1;
|
|
}
|
|
StrCpyN(pszVer, c_szBlds[i], cch);
|
|
*psv = (SETUPVER)i;
|
|
fTranslated = TRUE;
|
|
break;
|
|
}
|
|
|
|
return fTranslated;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: DetectPrevVer
|
|
|
|
SYNOPSIS: Called when there is no ver info for current app
|
|
|
|
********************************************************************/
|
|
SETUPVER DetectPrevVer(LPTSTR pszVer, int cch)
|
|
{
|
|
SETUPVER sv;
|
|
TCHAR szVer[VERLEN] = {0};
|
|
WORD wVer[4];
|
|
TCHAR szFile[MAX_PATH];
|
|
TCHAR szFile2[MAX_PATH];
|
|
UINT uLen;
|
|
DWORD dwAttr;
|
|
|
|
Assert(pszVer);
|
|
StrCpyN(szFile, si.szSysDir, ARRAYSIZE(szFile));
|
|
uLen = lstrlen(szFile);
|
|
|
|
switch (si.saApp)
|
|
{
|
|
case APP_OE:
|
|
LOG("Sniffing for OE... Detected:");
|
|
|
|
StrCpyN(&szFile[uLen], c_szMAILNEWS, ARRAYSIZE(szFile) - uLen);
|
|
|
|
// See what version we've told IE Setup, is installed
|
|
// Or what version msimn.exe is (to cover the case in which the
|
|
// ASetup info has been damaged - OE 5.01 80772)
|
|
if (GetASetupVer(c_szOEGUID, wVer, szVer, ARRAYSIZE(szVer)) ||
|
|
SUCCEEDED(GetExeVer(c_szOldMainExe, wVer, szVer, ARRAYSIZE(szVer))))
|
|
sv = ConvertVerToEnum(wVer);
|
|
else
|
|
{
|
|
// 1.0 or none
|
|
|
|
// Does mailnews.dll exist?
|
|
if(0xFFFFFFFF == GetFileAttributes(szFile))
|
|
sv = VER_NONE;
|
|
else
|
|
sv = VER_1_0;
|
|
}
|
|
|
|
// If active setup, these will be rollably deleted
|
|
if (CALLER_IE != si.caller)
|
|
FORCE_DEL(szFile);
|
|
|
|
LOG2(c_szLOGVERS[sv]);
|
|
break;
|
|
|
|
case APP_WAB:
|
|
LOG("Sniffing for WAB... Detected:");
|
|
|
|
StrCpyN(&szFile[uLen], c_szWAB32, ARRAYSIZE(szFile) - uLen);
|
|
StrCpyN(szFile2, si.szWinDir, ARRAYSIZE(szFile2));
|
|
StrCatBuff(szFile2, c_szWABEXE, ARRAYSIZE(szFile2));
|
|
|
|
if (GetASetupVer(c_szWABGUID, wVer, szVer, ARRAYSIZE(szVer)))
|
|
{
|
|
// 5.0 or later
|
|
if (5 == wVer[0])
|
|
sv = VER_5_0;
|
|
else
|
|
sv = VER_MAX;
|
|
}
|
|
else if (GetASetupVer(c_szOEGUID, wVer, szVer, ARRAYSIZE(szVer)) ||
|
|
SUCCEEDED(GetExeVer(c_szOldMainExe, wVer, szVer, ARRAYSIZE(szVer))))
|
|
{
|
|
// 4.0x or 5.0 Beta 1
|
|
if (5 == wVer[0])
|
|
sv = VER_5_0_B1;
|
|
else if (4 == wVer[0])
|
|
sv = VER_4_0;
|
|
else
|
|
sv = VER_MAX;
|
|
}
|
|
else
|
|
{
|
|
// 1.0, 1.1 or none
|
|
|
|
// WAB32.dll around?
|
|
if(0xFFFFFFFF == GetFileAttributes(szFile))
|
|
sv = VER_NONE;
|
|
else
|
|
{
|
|
// \Windows\Wab.exe around?
|
|
if(0xFFFFFFFF == GetFileAttributes(szFile2))
|
|
sv = VER_1_0;
|
|
else
|
|
sv = VER_1_1;
|
|
}
|
|
}
|
|
|
|
// If active setup, these will be rollably deleted
|
|
if (CALLER_IE != si.caller)
|
|
{
|
|
FORCE_DEL(szFile);
|
|
FORCE_DEL(szFile2);
|
|
}
|
|
|
|
LOG2(c_szLOGVERS[sv]);
|
|
break;
|
|
|
|
default:
|
|
sv = VER_NONE;
|
|
}
|
|
|
|
// Figure out the build number for this ver
|
|
if (szVer[0])
|
|
// Use real ver
|
|
StrCpyN(pszVer, szVer, cch);
|
|
else
|
|
// Fake Ver
|
|
StrCpyN(pszVer, sv > sizeof(c_szBlds)/sizeof(c_szBlds[0]) ? c_szBlds[0] : c_szBlds[sv], cch);
|
|
|
|
|
|
return sv;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: HandleVersionInfo
|
|
|
|
********************************************************************/
|
|
void HandleVersionInfo(BOOL fAfterInstall)
|
|
{
|
|
HKEY hkeyT,hkey;
|
|
DWORD cb, dwDisp;
|
|
TCHAR szCurrVer[VERLEN]={0};
|
|
TCHAR szPrevVer[VERLEN]={0};
|
|
LPTSTR psz;
|
|
SETUPVER svCurr = VER_MAX, svPrev = VER_MAX;
|
|
WORD wVer[4];
|
|
BOOL fReg=FALSE;
|
|
|
|
Assert(si.pszVerInfo);
|
|
|
|
// Are we dealing with the "current" entry?
|
|
if (fAfterInstall)
|
|
{
|
|
LPCTSTR pszGUID;
|
|
TCHAR szVer[VERLEN];
|
|
|
|
switch (si.saApp)
|
|
{
|
|
case APP_OE:
|
|
pszGUID = c_szOEGUID;
|
|
break;
|
|
|
|
case APP_WAB:
|
|
pszGUID = c_szWABGUID;
|
|
break;
|
|
|
|
default:
|
|
AssertSz(FALSE, "Unknown app is trying to be installed. Abandon hope...");
|
|
return;
|
|
}
|
|
|
|
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, si.pszVerInfo, 0, NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_SET_VALUE, NULL, &hkeyT, &dwDisp))
|
|
{
|
|
if (!GetASetupVer(pszGUID, wVer, szVer, ARRAYSIZE(szVer)))
|
|
{
|
|
// Uh oh, couldn't find our ASetup key - this is not good!
|
|
MsgBox(NULL, IDS_WARN_NOASETUPVER, MB_ICONEXCLAMATION, MB_OK);
|
|
RegSetValueEx(hkeyT, c_szRegCurrVer, 0, REG_SZ, (LPBYTE)c_szBLDnew, (lstrlen(c_szBLDnew) + 1) * sizeof(TCHAR));
|
|
}
|
|
else
|
|
RegSetValueEx(hkeyT, c_szRegCurrVer, 0, REG_SZ, (LPBYTE)szVer, (lstrlen(szVer) + 1) * sizeof(TCHAR));
|
|
|
|
RegCloseKey(hkeyT);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Handling "Previous" entry...
|
|
|
|
// Always try to use the version info
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, si.pszVerInfo, 0, KEY_QUERY_VALUE, &hkeyT))
|
|
{
|
|
cb = sizeof(szPrevVer);
|
|
RegQueryValueEx(hkeyT, c_szRegPrevVer, NULL, NULL, (LPBYTE)szPrevVer, &cb);
|
|
// Change to a bld # if needed
|
|
if (!TranslateVers(&svPrev, szPrevVer, ARRAYSIZE(szPrevVer)))
|
|
{
|
|
// Convert bld to enum
|
|
ConvertStrToVer(szPrevVer, wVer);
|
|
svPrev = ConvertVerToEnum(wVer);
|
|
}
|
|
|
|
// If version info shows that a ver info aware version was uninstalled, throw out the info
|
|
// and redetect
|
|
if (VER_NONE == svPrev)
|
|
// Sniff the machine for current version
|
|
svCurr = DetectPrevVer(szCurrVer, ARRAYSIZE(szCurrVer));
|
|
else
|
|
{
|
|
// There was previous version reg goo - and it's legit
|
|
fReg = TRUE;
|
|
|
|
cb = sizeof(szCurrVer);
|
|
RegQueryValueEx(hkeyT, c_szRegCurrVer, NULL, NULL, (LPBYTE)szCurrVer, &cb);
|
|
// Change to a bld # if needed
|
|
if (!TranslateVers(&svCurr, szCurrVer, ARRAYSIZE(szCurrVer)))
|
|
{
|
|
// Convert bld to enum
|
|
ConvertStrToVer(szCurrVer, wVer);
|
|
svCurr = ConvertVerToEnum(wVer);
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkeyT);
|
|
}
|
|
else
|
|
{
|
|
// Sniff the machine for current version
|
|
svCurr = DetectPrevVer(szCurrVer, ARRAYSIZE(szCurrVer));
|
|
}
|
|
|
|
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, si.pszVerInfo, 0, NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_SET_VALUE, NULL, &hkeyT, &dwDisp))
|
|
{
|
|
// Should we change the previous version entry?
|
|
if (VER_6_0 != svCurr)
|
|
{
|
|
// Know this is B1 OE if we translated
|
|
// Know this is B1 WAB if we detected it
|
|
if (VER_5_0_B1 == svCurr)
|
|
{
|
|
RegSetValueEx(hkeyT, c_szRegInterimVer, 0, REG_DWORD, (LPBYTE)&svCurr, sizeof(SETUPVER));
|
|
// Did we read a previous value?
|
|
if (fReg)
|
|
// As there were reg entries, just translate the previous entry
|
|
psz = szPrevVer;
|
|
else
|
|
{
|
|
// We don't have a bld number and yet we are B1, better be the WAB
|
|
Assert(APP_WAB == si.saApp);
|
|
|
|
// Peek at OE's ver info
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegVerInfo, 0, KEY_QUERY_VALUE, &hkey))
|
|
{
|
|
cb = sizeof(szPrevVer);
|
|
// Read a build or a string
|
|
RegQueryValueExA(hkey, c_szRegPrevVer, NULL, NULL, (LPBYTE)szPrevVer, &cb);
|
|
// If it's a string, convert it to a build
|
|
TranslateVers(&svPrev, szPrevVer, ARRAYSIZE(szPrevVer));
|
|
|
|
// We'll use the build (translated or direct)
|
|
psz = szPrevVer;
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RegDeleteValue(hkeyT, c_szRegInterimVer);
|
|
// Make the old current ver, the previous ver
|
|
psz = szCurrVer;
|
|
}
|
|
|
|
RegSetValueEx(hkeyT, c_szRegPrevVer, 0, REG_SZ, (LPBYTE)psz, (lstrlen(psz) + 1) * sizeof(TCHAR));
|
|
}
|
|
|
|
RegCloseKey(hkeyT);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: UpgradeOESettings
|
|
|
|
********************************************************************/
|
|
BOOL UpgradeOESettings(SETUPVER svPrev, HKEY hkeyDest)
|
|
{
|
|
LPCTSTR pszSrc;
|
|
HKEY hkeySrc;
|
|
BOOL fMig;
|
|
|
|
Assert(hkeyDest);
|
|
|
|
// Figure out where the data is coming FROM...
|
|
switch (svPrev)
|
|
{
|
|
default:
|
|
// Nothing to do
|
|
return TRUE;
|
|
|
|
case VER_4_0:
|
|
pszSrc = c_szRegFlat;
|
|
break;
|
|
|
|
case VER_5_0_B1:
|
|
pszSrc = c_szRegRoot;
|
|
break;
|
|
}
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, pszSrc, 0, KEY_READ, &hkeySrc))
|
|
{
|
|
CopyRegistry(hkeySrc, hkeyDest);
|
|
RegCloseKey(hkeySrc);
|
|
|
|
fMig = TRUE;
|
|
}
|
|
else
|
|
fMig = FALSE;
|
|
|
|
return fMig;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: UpgradeWABSettings
|
|
|
|
********************************************************************/
|
|
BOOL UpgradeWABSettings(SETUPVER svPrev, HKEY hkeyDest)
|
|
{
|
|
LPCTSTR pszSrc;
|
|
BOOL fMig;
|
|
HKEY hkeySrc;
|
|
|
|
Assert(hkeyDest);
|
|
|
|
// Figure out where the data is coming FROM...
|
|
switch (svPrev)
|
|
{
|
|
default:
|
|
// Nothing to do
|
|
return TRUE;
|
|
|
|
case VER_4_0:
|
|
case VER_5_0_B1:
|
|
pszSrc = c_szInetAcctMgrRegKey;
|
|
break;
|
|
}
|
|
|
|
|
|
// IAM\Accounts
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, pszSrc, 0, KEY_READ, &hkeySrc))
|
|
{
|
|
CopyRegistry(hkeySrc, hkeyDest);
|
|
RegCloseKey(hkeySrc);
|
|
|
|
fMig = TRUE;
|
|
}
|
|
else
|
|
fMig = FALSE;
|
|
|
|
return fMig;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: UpgradeOESettingsToMU
|
|
|
|
SYNOPSIS: Copies forward settings as needed and returns TRUE
|
|
if we did migrate.
|
|
|
|
********************************************************************/
|
|
BOOL UpgradeOESettingsToMU()
|
|
{
|
|
SETUPVER svMachinePrev = VER_NONE, svUserPrev = VER_NONE;
|
|
HKEY hkeySrc, hkeyID;
|
|
DWORD dwTemp;
|
|
BOOL fUpgraded = FALSE, fAlreadyDone = FALSE;
|
|
IUserIdentityManager *pManager=NULL;
|
|
IUserIdentity *pIdentity=NULL;
|
|
TCHAR szVer[VERLEN];
|
|
HKEY hkeySettings, hkeyT;
|
|
DWORD dwDisp;
|
|
GUID guid;
|
|
int i;
|
|
|
|
// Get an identity manager
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_UserIdentityManager, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IUserIdentityManager, (void **)&pManager)))
|
|
{
|
|
Assert(pManager);
|
|
|
|
// Get Default Identity
|
|
if (SUCCEEDED(pManager->GetIdentityByCookie((GUID*)&UID_GIBC_DEFAULT_USER, &pIdentity)))
|
|
{
|
|
Assert(pIdentity);
|
|
|
|
// Ensure that we have an identity and can get to its registry
|
|
if (SUCCEEDED(pIdentity->OpenIdentityRegKey(KEY_WRITE, &hkeyID)))
|
|
{
|
|
// Create the place for their OE settings
|
|
if (ERROR_SUCCESS == RegCreateKeyEx(hkeyID, c_szRegRoot, 0, NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE, NULL, &hkeySettings, &dwDisp))
|
|
{
|
|
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, c_szRegSharedSetup, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkeyT, &dwDisp))
|
|
{
|
|
// Is there already a migrated default user?
|
|
if (ERROR_SUCCESS != RegQueryValueEx(hkeyT, c_szSettingsToLWP, 0, &dwTemp, NULL, NULL))
|
|
{
|
|
// Record that we are about to do
|
|
ZeroMemory(&guid, sizeof(guid));
|
|
pIdentity->GetCookie(&guid);
|
|
RegSetValueEx(hkeyT, c_szSettingsToLWP, 0, REG_BINARY, (LPBYTE)&guid, sizeof(guid));
|
|
|
|
// Note today's version
|
|
if (GetASetupVer(c_szOEGUID, NULL, szVer, ARRAYSIZE(szVer)))
|
|
RegSetValueEx(hkeyT, c_szSettingsToLWPVer, 0, REG_SZ, (LPBYTE)szVer, sizeof(szVer));
|
|
|
|
// Close the key now as it will be a while before we leave this block
|
|
RegCloseKey(hkeyT);
|
|
|
|
// Figure out which version's settings we will be looking for
|
|
if (!InterimBuild(&svMachinePrev))
|
|
GetVerInfo(NULL, &svMachinePrev);
|
|
|
|
// Go backwards through list of versions, and look for user info
|
|
// the same age or older than the previous version on the machine
|
|
for (i = svMachinePrev; i >= VER_NONE; i--)
|
|
{
|
|
if (bVerInfoExists((SETUPVER)i))
|
|
{
|
|
svUserPrev = (SETUPVER)i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Begin with default values
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegDefaultSettings, 0, KEY_READ, &hkeySrc))
|
|
{
|
|
CopyRegistry(hkeySrc, hkeySettings);
|
|
RegCloseKey(hkeySrc);
|
|
}
|
|
|
|
// Apply previous version settings if any
|
|
fUpgraded = UpgradeOESettings(svUserPrev, hkeySettings);
|
|
|
|
// Tell msoe.dll's migration code that this is not a new user and migration should be done
|
|
dwDisp = 0;
|
|
RegSetValueEx(hkeySettings, c_szOEVerStamp, 0, REG_DWORD, (LPBYTE)&dwDisp, sizeof(dwDisp));
|
|
}
|
|
else
|
|
{
|
|
// Check for TechBeta Builds
|
|
if (REG_DWORD == dwTemp)
|
|
{
|
|
ZeroMemory(&guid, sizeof(guid));
|
|
pIdentity->GetCookie(&guid);
|
|
RegSetValueEx(hkeyT, c_szSettingsToLWP, 0, REG_BINARY, (LPBYTE)&guid, sizeof(guid));
|
|
}
|
|
fAlreadyDone = TRUE;
|
|
RegCloseKey(hkeyT);
|
|
}
|
|
}
|
|
RegCloseKey(hkeySettings);
|
|
}
|
|
RegCloseKey(hkeyID);
|
|
}
|
|
pIdentity->Release();
|
|
}
|
|
pManager->Release();
|
|
}
|
|
|
|
return fAlreadyDone ? FALSE : fUpgraded;
|
|
}
|
|
|
|
|
|
BOOL UpgradeSettings()
|
|
{
|
|
switch (si.saApp)
|
|
{
|
|
case APP_OE:
|
|
return UpgradeOESettingsToMU();
|
|
|
|
case APP_WAB:
|
|
return TRUE;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: bOEVerInfoExists
|
|
|
|
********************************************************************/
|
|
BOOL bOEVerInfoExists(SETUPVER sv)
|
|
{
|
|
BOOL bExists = FALSE;
|
|
HKEY hkey;
|
|
|
|
switch (sv)
|
|
{
|
|
default:
|
|
bExists = FALSE;
|
|
break;
|
|
|
|
case VER_1_0:
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegRoot_V1, 0 ,KEY_QUERY_VALUE,&hkey))
|
|
{
|
|
bExists = (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szRegStoreRootDir, NULL, NULL, NULL, NULL));
|
|
RegCloseKey(hkey);
|
|
}
|
|
break;
|
|
|
|
case VER_4_0:
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegFlat,0,KEY_QUERY_VALUE,&hkey))
|
|
{
|
|
bExists = (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szRegStoreRootDir, NULL, NULL, NULL, NULL));
|
|
RegCloseKey(hkey);
|
|
}
|
|
break;
|
|
|
|
case VER_5_0_B1:
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegRoot ,0 , KEY_QUERY_VALUE, &hkey))
|
|
{
|
|
bExists = TRUE;
|
|
RegCloseKey(hkey);
|
|
}
|
|
break;
|
|
}
|
|
return bExists;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: bWABVerInfoExists
|
|
|
|
********************************************************************/
|
|
BOOL bWABVerInfoExists(SETUPVER sv)
|
|
{
|
|
BOOL bExists = FALSE;
|
|
HKEY hkey;
|
|
|
|
switch (sv)
|
|
{
|
|
default:
|
|
bExists = FALSE;
|
|
break;
|
|
|
|
case VER_1_1:
|
|
case VER_1_0:
|
|
bExists = bOEVerInfoExists(VER_1_0);
|
|
break;
|
|
|
|
case VER_4_0:
|
|
case VER_5_0_B1:
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, c_szInetAcctMgrRegKey, 0, KEY_QUERY_VALUE,&hkey))
|
|
{
|
|
bExists = TRUE;
|
|
RegCloseKey(hkey);
|
|
}
|
|
break;
|
|
}
|
|
return bExists;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: bVerInfoExists
|
|
|
|
********************************************************************/
|
|
BOOL bVerInfoExists(SETUPVER sv)
|
|
{
|
|
switch (si.saApp)
|
|
{
|
|
case APP_OE:
|
|
return bOEVerInfoExists(sv);
|
|
|
|
case APP_WAB:
|
|
return bWABVerInfoExists(sv);
|
|
default:
|
|
return FALSE;
|
|
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: PreRollable
|
|
|
|
********************************************************************/
|
|
void PreRollable()
|
|
{
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: ApplyActiveSetupVer()
|
|
|
|
SYNOPS
|
|
|
|
********************************************************************/
|
|
void ApplyActiveSetupVer()
|
|
{
|
|
TCHAR szVer[VERLEN];
|
|
TCHAR szPath[MAX_PATH];
|
|
LPCTSTR pszGuid;
|
|
LPCTSTR pszVerString;
|
|
int cLen;
|
|
HKEY hkey;
|
|
|
|
switch (si.saApp)
|
|
{
|
|
case APP_OE:
|
|
pszGuid = c_szOEGUID;
|
|
pszVerString = c_szVersionOE;
|
|
break;
|
|
|
|
case APP_WAB:
|
|
pszGuid = c_szWABGUID;
|
|
pszVerString = c_szValueVersion;
|
|
break;
|
|
|
|
default:
|
|
AssertSz(FALSE, "Applying ActiveSetupVer for unknown APP!");
|
|
return;
|
|
}
|
|
|
|
// Get the version out of the INF file
|
|
wnsprintf(szPath, ARRAYSIZE(szPath), c_szFileEntryFmt, si.szInfDir, si.pszInfFile);
|
|
cLen = GetPrivateProfileString(c_szStringSection, pszVerString, c_szBLDnew, szVer, ARRAYSIZE(szVer), szPath);
|
|
|
|
// Write the version in the registry
|
|
wnsprintf(szPath, ARRAYSIZE(szPath), c_szPathFileFmt, c_szRegASetup, pszGuid);
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szPath, 0, KEY_SET_VALUE, &hkey))
|
|
{
|
|
RegSetValueEx(hkey, c_szValueVersion, 0, REG_SZ, (LPBYTE)szVer, (cLen+1)*sizeof(TCHAR));
|
|
RegCloseKey(hkey);
|
|
|
|
#ifdef _WIN64
|
|
// !! HACKHACK !!
|
|
// We put the same string in the Wow6432Node of the registry so that the 32-bit Outlook2000 running on ia64
|
|
// will not complain that OE is not installed.
|
|
//
|
|
// This should not be necessary, but currently (and it might stay this way) msoe50.inf is adding RunOnceEx entries
|
|
// under the Wow6432Node and the are not being "reflected" to the normal HKLM branch. Thus, the below reg entry is
|
|
// never added.
|
|
|
|
wnsprintf(szPath, ARRAYSIZE(szPath), c_szPathFileFmt, TEXT("Software\\Wow6432Node\\Microsoft\\Active Setup\\Installed Components"), pszGuid);
|
|
|
|
// call RegCreateKeyEx in case the 32-bit stuff hasen't run yet
|
|
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE,
|
|
szPath,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_SET_VALUE,
|
|
NULL,
|
|
&hkey,
|
|
NULL))
|
|
{
|
|
RegSetValueEx(hkey, c_szValueVersion, 0, REG_SZ, (LPBYTE)szVer, (cLen+1)*sizeof(TCHAR));
|
|
RegCloseKey(hkey);
|
|
}
|
|
#endif // _WIN64
|
|
}
|
|
else
|
|
{
|
|
LOG("[ERROR]: App's ASetup Key hasn't been created.");
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: GetDirNames
|
|
|
|
SYNOPSIS: Figures out commonly used dir names
|
|
dwWant should have the nth bit set if you want the
|
|
nth string argument set
|
|
|
|
********************************************************************/
|
|
DWORD GetDirNames(DWORD dwWant, LPTSTR pszOE, LPTSTR pszSystem, LPTSTR pszServices, LPTSTR pszStationery)
|
|
{
|
|
HKEY hkeyT;
|
|
DWORD cb;
|
|
DWORD dwType;
|
|
TCHAR szTemp[MAX_PATH];
|
|
TCHAR szTemp2[MAX_PATH];
|
|
DWORD dwReturned = 0;
|
|
|
|
ZeroMemory(szTemp, ARRAYSIZE(szTemp));
|
|
// Do they want the OE Install Directory?
|
|
if (dwWant & 1)
|
|
{
|
|
Assert(pszOE);
|
|
pszOE[0] = 0;
|
|
|
|
// OE Install Dir
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegFlat, 0, KEY_QUERY_VALUE, &hkeyT))
|
|
{
|
|
cb = MAX_PATH * sizeof(TCHAR);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkeyT, c_szInstallRoot, 0, &dwType, (LPBYTE)pszOE, &cb))
|
|
{
|
|
// Forget about the null in count
|
|
cb--;
|
|
|
|
if (*CharPrev(pszOE, pszOE+cb) != '\\')
|
|
{
|
|
pszOE[cb++] = '\\';
|
|
pszOE[cb] = 0;
|
|
}
|
|
|
|
if (REG_EXPAND_SZ == dwType)
|
|
{
|
|
ExpandEnvironmentStrings(pszOE, szTemp, ARRAYSIZE(szTemp));
|
|
StrCpyN(pszOE, szTemp, MAX_PATH);
|
|
}
|
|
|
|
dwReturned |= 1;
|
|
}
|
|
|
|
RegCloseKey(hkeyT);
|
|
}
|
|
}
|
|
|
|
// Do they want the Common Files\System Directory?
|
|
if (dwWant & 2)
|
|
{
|
|
Assert(pszSystem);
|
|
pszSystem[0] = 0;
|
|
}
|
|
|
|
// Do they want the Common Files\Services Directory?
|
|
if (dwWant & 4)
|
|
{
|
|
Assert(pszServices);
|
|
pszServices[0] = 0;
|
|
}
|
|
|
|
// Do they want the Common Files\Microsoft Shared\Stationery Directory?
|
|
if (dwWant & 8)
|
|
{
|
|
Assert(pszStationery);
|
|
pszStationery[0] = 0;
|
|
}
|
|
|
|
// Program Files\Common Files\System and \Services
|
|
if (dwWant & (2 | 4 | 8))
|
|
{
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegWinCurrVer, 0, KEY_QUERY_VALUE, &hkeyT))
|
|
{
|
|
cb = sizeof(szTemp2);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkeyT, c_szCommonFilesDir, 0, &dwType, (LPBYTE)szTemp2, &cb))
|
|
{
|
|
// Forget about the null in count
|
|
cb--;
|
|
|
|
if (*CharPrev(szTemp2, szTemp2+cb) != '\\')
|
|
{
|
|
szTemp2[cb++] = '\\';
|
|
szTemp2[cb]=0;
|
|
}
|
|
|
|
if (REG_EXPAND_SZ == dwType)
|
|
{
|
|
ExpandEnvironmentStrings(szTemp2, szTemp, ARRAYSIZE(szTemp));
|
|
StrCpyN(szTemp2, szTemp, ARRAYSIZE(szTemp2));
|
|
}
|
|
|
|
cb = lstrlen(szTemp2);
|
|
|
|
if (dwWant & 2)
|
|
{
|
|
StrCpyN(pszSystem, szTemp2, MAX_PATH);
|
|
|
|
// "System" could be localized
|
|
LoadString(g_hInstance, IDS_DIR_SYSTEM, &pszSystem[cb], MAX_PATH-cb);
|
|
|
|
dwWant |= 2;
|
|
}
|
|
|
|
if (dwWant & 4)
|
|
{
|
|
StrCpyN(pszServices, szTemp2, MAX_PATH);
|
|
|
|
// "Services" could be localized
|
|
LoadString(g_hInstance, IDS_DIR_SERVICES, &pszServices[cb], MAX_PATH-cb);
|
|
|
|
dwWant |= 4;
|
|
}
|
|
|
|
if (dwWant & 8)
|
|
{
|
|
StrCpyN(pszStationery, szTemp2, MAX_PATH);
|
|
|
|
// "Microsoft Shared\Stationery could be localized
|
|
LoadString(g_hInstance, IDS_DIR_STAT, &pszStationery[cb], MAX_PATH-cb);
|
|
|
|
dwWant |= 8;
|
|
}
|
|
}
|
|
RegCloseKey(hkeyT);
|
|
}
|
|
}
|
|
|
|
return dwWant;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: RepairBeta1Install
|
|
|
|
SYNOPSIS: See what happens when people make late design decisions!
|
|
|
|
********************************************************************/
|
|
typedef struct tagRepairInfo
|
|
{
|
|
LPTSTR pszFile;
|
|
LPTSTR pszDir;
|
|
} REPAIRINFO;
|
|
|
|
typedef struct tagRegInfo
|
|
{
|
|
LPCTSTR pszRoot;
|
|
LPTSTR pszSub;
|
|
LPCTSTR pszValue;
|
|
} REGINFO;
|
|
|
|
void RepairBeta1Install()
|
|
{
|
|
HKEY hkeyOE, hkeyWAB;
|
|
TCHAR szOEUninstallFile [MAX_PATH];
|
|
TCHAR szOEUninstallDir [MAX_PATH];
|
|
TCHAR szWABUninstallFile[MAX_PATH];
|
|
TCHAR szWABUninstallDir [MAX_PATH];
|
|
TCHAR szTemp [MAX_PATH];
|
|
DWORD cb, dwType, dwTemp;
|
|
|
|
LOG("Attempting to repair Beta 1 Install...");
|
|
|
|
ZeroMemory(szTemp, ARRAYSIZE(szTemp));
|
|
switch (si.saApp)
|
|
{
|
|
case APP_WAB:
|
|
// Do we have the needed Advpack functionality?
|
|
if (NULL == si.pfnAddDel || NULL == si.pfnRegRestore)
|
|
{
|
|
LOG("[ERROR]: Extended Advpack functionality is needed but could not be found");
|
|
break;
|
|
}
|
|
|
|
// Figure out where the OE backup is
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegAdvInfoOE, 0, KEY_READ, &hkeyOE))
|
|
{
|
|
// Make sure we can create the AddressBook Key
|
|
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szRegAdvInfoWAB, 0, NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_READ | KEY_WRITE, NULL, &hkeyWAB, &cb))
|
|
{
|
|
cb = sizeof(szOEUninstallFile);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkeyOE, c_szBackupFileName, 0, &dwType, (LPBYTE)szOEUninstallFile, &cb))
|
|
{
|
|
UINT uLenWAB, uLenOE;
|
|
|
|
if (REG_EXPAND_SZ == dwType)
|
|
{
|
|
ExpandEnvironmentStrings(szOEUninstallFile, szTemp, ARRAYSIZE(szTemp));
|
|
StrCpyN(szOEUninstallFile, szTemp, ARRAYSIZE(szOEUninstallFile));
|
|
|
|
// Figure out where to change the extension for OE (4 = .DAT)
|
|
uLenOE = lstrlen(szOEUninstallFile) - 4;
|
|
}
|
|
else
|
|
// Figure out where to change the extension for OE (5 = .DAT + NULL from Query)
|
|
uLenOE = cb - 5;
|
|
|
|
// Can we get to it?
|
|
if (0xFFFFFFFF != GetFileAttributes(szOEUninstallFile))
|
|
{
|
|
LPTSTR pszSlash, pszCurrent;
|
|
|
|
cb = sizeof(szOEUninstallDir);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkeyOE, c_szBackupPath, 0, &dwType, (LPBYTE)szOEUninstallDir, &cb))
|
|
{
|
|
if (REG_EXPAND_SZ == dwType)
|
|
{
|
|
ExpandEnvironmentStrings(szOEUninstallDir, szTemp, ARRAYSIZE(szTemp));
|
|
StrCpyN(szOEUninstallDir, szTemp, ARRAYSIZE(szOEUninstallDir));
|
|
}
|
|
|
|
// Figure out the destination for the file
|
|
StrCpyN(szWABUninstallDir, szOEUninstallDir, ARRAYSIZE(szWABUninstallDir));
|
|
|
|
pszCurrent = szWABUninstallDir;
|
|
pszSlash = NULL;
|
|
|
|
// Parse the string looking for the last slash
|
|
while (*pszCurrent)
|
|
{
|
|
if (*pszCurrent == TEXT('\\'))
|
|
pszSlash = CharNext(pszCurrent);
|
|
|
|
pszCurrent = CharNext(pszCurrent);
|
|
}
|
|
|
|
if (NULL != pszSlash)
|
|
{
|
|
TCHAR szOE [MAX_PATH];
|
|
TCHAR szCommonSys[MAX_PATH];
|
|
TCHAR szHelp [MAX_PATH];
|
|
TCHAR szStat [MAX_PATH];
|
|
TCHAR szServices [MAX_PATH];
|
|
TCHAR szFiles[5 * MAX_PATH];
|
|
|
|
int i,j;
|
|
|
|
szOE[0] = 0;
|
|
szCommonSys[0] = 0;
|
|
szHelp[0] = 0;
|
|
szStat[0] = 0;
|
|
szServices[0] = 0;
|
|
|
|
#if 0
|
|
// Files to remove from OE and WAB - 0
|
|
const REPAIRINFO BOTHDel[]= {};
|
|
#endif
|
|
|
|
// Files to remove from OE - 19
|
|
const REPAIRINFO OEDel[] = {
|
|
{"wab32.dll", szCommonSys}, {"wab.hlp" , szHelp}, {"wab.chm", szHelp}, {"wab.exe", szOE},
|
|
{"wabmig.exe", szOE}, {"wabimp.dll", szOE}, {"wabfind.dll", szOE}, {"msoeacct.dll", si.szSysDir},
|
|
{"msoert2.dll", si.szSysDir}, {"msoeacct.hlp", szHelp}, {"conn_oe.hlp", szHelp}, {"conn_oe.cnt", szHelp},
|
|
{"wab.cnt", szHelp}, {"wab32.dll", si.szSysDir}, {"wabfind.dll", si.szSysDir}, {"wabimp.dll", si.szSysDir},
|
|
{"wab.exe", si.szWinDir}, {"wabmig.exe", si.szWinDir}};
|
|
|
|
// Files to remove from WAB - 62
|
|
const REPAIRINFO WABDel[] = {
|
|
{"msoeres.dll", szOE}, {"msoe.dll", szOE}, {"msoe.hlp", szHelp}, {"msoe.chm", szHelp},
|
|
{"msoe.txt", szOE}, {"oeimport.dll", szOE}, {"inetcomm.dll", si.szSysDir}, {"inetres.dll", si.szSysDir},
|
|
{"msoemapi.dll", si.szSysDir}, {"msimn.exe", szOE}, {"inetcomm.hlp", szHelp}, {"msimn.cnt", szHelp},
|
|
{"msimn.hlp", szHelp}, {"msimn.chm", szHelp}, {"msimn.gid", szHelp}, {"_isetup.exe", szOE},
|
|
{"msimnui.dll", szOE}, {"msimn.txt", szOE}, {"mnlicens.txt", szOE}, {"msimnimp.dll", szOE},
|
|
{"msimn.inf", si.szInfDir}, {"msoert.dll", si.szSysDir},
|
|
{"bigfoot.bmp", szServices}, {"verisign.bmp", szServices}, {"yahoo.bmp", szServices},
|
|
{"infospce.bmp", szServices}, {"infospbz.bmp", szServices}, {"swtchbrd.bmp", szServices},
|
|
|
|
|
|
{"Baby News.htm", szStat}, {"Balloon Party Invitation.htm", szStat},
|
|
{"Chicken Soup.htm", szStat}, {"Formal Announcement.htm", szStat},
|
|
{"For Sale.htm", szStat}, {"Fun Bus.htm", szStat},
|
|
{"Holiday Letter.htm", szStat}, {"Mabel.htm", szStat},
|
|
{"Running Birthday.htm", szStat}, {"Story Book.htm", szStat},
|
|
{"Tiki Lounge.htm", szStat}, {"Ivy.htm", szStat},
|
|
{"One Green Balloon.gif", szStat}, {"Baby News Bkgrd.gif", szStat},
|
|
{"Chess.gif", szStat}, {"Chicken Soup Bkgrd.gif", szStat},
|
|
{"Formal Announcement Bkgrd.gif", szStat}, {"For Sale Bkgrd.gif", szStat},
|
|
{"FunBus.gif", szStat}, {"Holiday Letter Bkgrd.gif", szStat},
|
|
{"MabelT.gif", szStat}, {"MabelB.gif", szStat},
|
|
{"Running.gif", szStat}, {"Santa Workshop.gif", szStat},
|
|
{"Soup Bowl.gif", szStat}, {"Squiggles.gif", szStat},
|
|
{"StoryBook.gif", szStat}, {"Tiki.gif", szStat},
|
|
{"Christmas Trees.gif", szStat}, {"Ivy.gif", szStat},
|
|
{"Balloon Party Invitation Bkgrd.jpg", szStat}, {"Technical.htm", szStat},
|
|
{"Chess.htm", szStat}, {"Tech.gif", szStat}};
|
|
|
|
// Reg settings to remove from OE -
|
|
const REGINFO OERegDel[] = {
|
|
{c_szHKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\wab.exe", c_szEmpty},
|
|
{c_szHKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\wab.exe", c_szRegPath},
|
|
{c_szHKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\wabmig.exe", c_szEmpty},
|
|
{c_szHKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\wabmig.exe", c_szRegPath},
|
|
{c_szHKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\InternetMailNews", NULL}};
|
|
//{c_szHKLM, "Software\\Microsoft\\Outlook Express", c_szInstallRoot}};
|
|
|
|
const REGINFO WABRegDel[] = {
|
|
{c_szHKLM, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\OptionalComponents\\OutlookExpress", "Installed"},
|
|
{c_szHKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OutlookExpress", "DisplayName"},
|
|
{c_szHKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OutlookExpress", "UninstallString"},
|
|
{c_szHKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OutlookExpress", "QuietUninstallString"},
|
|
{c_szHKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OutlookExpress", c_szRequiresIESys},
|
|
{c_szHKLM, "Software\\Microsoft\\Outlook Express", "InstallRoot"},
|
|
{c_szHKLM, "Software\\Microsoft\\Outlook Express\\Inetcomm", "DllPath"},
|
|
{c_szHKLM, "Software\\Microsoft\\Outlook Express", "Beta"},
|
|
{c_szHKLM, "Software\\Clients\\Mail\\Outlook Express", NULL},
|
|
{c_szHKLM, "Software\\Clients\\News\\Outlook Express", NULL},
|
|
{c_szHKLM, "Software\\Clients\\Mail\\Internet Mail and News", NULL},
|
|
{c_szHKLM, "Software\\Clients\\News\\Internet Mail and News", NULL},
|
|
{c_szHKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\InternetMailNews", NULL}};
|
|
//{c_szHKLM, "Software\\Microsoft\\Outlook Express", c_szInstallRoot}};
|
|
|
|
|
|
// Append the path to the addressbook dir
|
|
StrCpyN(pszSlash, c_szWABComponent, ARRAYSIZE(szWABUninstallDir) - (DWORD)(pszSlash - szWABUninstallDir));
|
|
|
|
// Create a directory
|
|
CreateDirectoryEx(szOEUninstallDir, szWABUninstallDir, NULL);
|
|
|
|
// Copy Reg
|
|
CopyRegistry(hkeyOE, hkeyWAB);
|
|
|
|
// If running on 9X, copy the AINF file too
|
|
if (VER_PLATFORM_WIN32_WINDOWS == si.osv.dwPlatformId)
|
|
{
|
|
cb = sizeof(szTemp);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkeyOE, c_szBackupRegPathName, 0, NULL, (LPBYTE)szTemp, &cb))
|
|
{
|
|
// Can't be REG_EXPAND_SZ, this is Win9X!
|
|
|
|
// Strip all but the filename
|
|
pszCurrent = szTemp;
|
|
pszSlash = NULL;
|
|
|
|
// Parse the string looking for the last slash
|
|
while (*pszCurrent)
|
|
{
|
|
if ('\\' == *pszCurrent)
|
|
pszSlash = CharNext(pszCurrent);
|
|
|
|
pszCurrent = CharNext(pszCurrent);
|
|
}
|
|
|
|
if (pszSlash)
|
|
{
|
|
TCHAR szWABShortDir[MAX_PATH];
|
|
|
|
// Combine the WAB dir name and the name of the OE file
|
|
wnsprintf(szWABShortDir, ARRAYSIZE(szWABShortDir), c_szPathFileFmt, szWABUninstallDir, pszSlash);
|
|
|
|
// Shorten destination
|
|
GetShortPathName(szWABShortDir, szWABShortDir, ARRAYSIZE(szWABShortDir));
|
|
|
|
// Write it into the registry (+1 for the NULL)
|
|
RegSetValueEx(hkeyWAB, c_szBackupRegPathName, 0, REG_SZ, (LPBYTE)szWABShortDir, (lstrlen(szWABShortDir)+1)*sizeof(TCHAR));
|
|
|
|
// Copy the file
|
|
CopyFile(szTemp, szWABShortDir, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Figure out the path the to wab INI and DAT
|
|
StrCpyN(szWABUninstallFile, szWABUninstallDir, ARRAYSIZE(szWABUninstallFile));
|
|
|
|
// Add Slash and component
|
|
StrCatBuff(szWABUninstallFile, c_szSlashWABComponent, ARRAYSIZE(szWABUninstallFile));
|
|
|
|
// Calculate the length for extension placement
|
|
uLenWAB = lstrlen(szWABUninstallFile);
|
|
|
|
// Do the DAT first
|
|
StrCpyN(&szWABUninstallFile[uLenWAB], c_szDotDAT, ARRAYSIZE(szWABUninstallFile) - uLenWAB);
|
|
|
|
// Patch the path names in the registry
|
|
cb = (lstrlen(szWABUninstallDir) + 1) * sizeof(TCHAR);
|
|
RegSetValueEx(hkeyWAB, c_szBackupPath, 0, REG_SZ, (LPBYTE)szWABUninstallDir, cb);
|
|
cb = (lstrlen(szWABUninstallFile) + 1) * sizeof(TCHAR);
|
|
RegSetValueEx(hkeyWAB, c_szBackupFileName, 0, REG_SZ, (LPBYTE)szWABUninstallFile, cb);
|
|
|
|
// ---- CALCULATE DIRECTORY NAMES
|
|
dwTemp = GetDirNames(1 | 2 | 4 | 8, szOE, szCommonSys, szServices, szStat);
|
|
|
|
if (VER_PLATFORM_WIN32_WINDOWS == si.osv.dwPlatformId)
|
|
{
|
|
if (dwTemp & 1)
|
|
GetShortPathName(szOE, szOE, ARRAYSIZE(szOE));
|
|
if (dwTemp & 2)
|
|
GetShortPathName(szCommonSys, szCommonSys, ARRAYSIZE(szCommonSys));
|
|
if (dwTemp & 4)
|
|
GetShortPathName(szServices, szServices, ARRAYSIZE(szServices));
|
|
if (dwTemp & 8)
|
|
GetShortPathName(szStat, szStat, ARRAYSIZE(szStat));
|
|
}
|
|
|
|
// Help Dir
|
|
StrCpyN(szHelp, si.szWinDir, ARRAYSIZE(szHelp));
|
|
cb = lstrlen(szHelp);
|
|
LoadString(g_hInstance, IDS_DIR_HELP, &szHelp[cb], ARRAYSIZE(szHelp)-cb);
|
|
if (VER_PLATFORM_WIN32_WINDOWS == si.osv.dwPlatformId)
|
|
GetShortPathName(szHelp, szHelp, ARRAYSIZE(szHelp));
|
|
|
|
// ---- MANIPULATE FILES
|
|
|
|
// Copy the DAT file to AddressBook land
|
|
CopyFile(szOEUninstallFile, szWABUninstallFile, TRUE);
|
|
|
|
StrCpyN(&szOEUninstallFile[uLenOE], c_szDotINI, ARRAYSIZE(szOEUninstallFile) - uLenOE);
|
|
StrCpyN(&szWABUninstallFile[uLenWAB], c_szDotINI, ARRAYSIZE(szWABUninstallFile) - uLenWAB);
|
|
|
|
// Copy the INI file to AddressBook land
|
|
CopyFile(szOEUninstallFile, szWABUninstallFile, TRUE);
|
|
|
|
// Purge Files from OE - 5 at a time
|
|
for (i=0; i < ARRAYSIZE(OEDel);)
|
|
{
|
|
for (j=i, cb=0; i < ARRAYSIZE(OEDel) && i-j < 5; i++)
|
|
cb += wnsprintf(&szFiles[cb++], ARRAYSIZE(szFiles) - cb,
|
|
c_szFileEntryFmt, OEDel[i].pszDir, OEDel[i].pszFile);
|
|
szFiles[cb] = 0;
|
|
|
|
(*si.pfnAddDel)(szFiles, szOEUninstallDir, c_szOEComponent, AADBE_DEL_ENTRY);
|
|
}
|
|
|
|
// Purge Files from WAB - 5 at a time
|
|
for (i=0; i<ARRAYSIZE(WABDel);)
|
|
{
|
|
for (j=i, cb=0; i < ARRAYSIZE(WABDel) && i-j < 5; i++)
|
|
cb += wnsprintf(&szFiles[cb++], ARRAYSIZE(szFiles) - cb,
|
|
c_szFileEntryFmt, WABDel[i].pszDir, WABDel[i].pszFile);
|
|
szFiles[cb] = 0;
|
|
|
|
(*si.pfnAddDel)(szFiles, szWABUninstallDir, c_szWABComponent, AADBE_DEL_ENTRY);
|
|
}
|
|
|
|
|
|
// ---- REPAIR Registry
|
|
HKEY hkeyOEBak=NULL;
|
|
HKEY hkeyWABBak=NULL;
|
|
|
|
if (VER_PLATFORM_WIN32_WINDOWS != si.osv.dwPlatformId)
|
|
{
|
|
// On non-Win95, we need to open a sub key of the backup info
|
|
RegOpenKeyEx(hkeyOE, c_szRegBackup, 0, KEY_READ | KEY_WRITE, &hkeyOEBak);
|
|
RegOpenKeyEx(hkeyWAB, c_szRegBackup, 0, KEY_READ | KEY_WRITE, &hkeyWABBak);
|
|
}
|
|
else
|
|
{
|
|
hkeyOEBak = hkeyOE;
|
|
hkeyWABBak = hkeyWAB;
|
|
}
|
|
|
|
if (NULL != hkeyOEBak)
|
|
{
|
|
// Remove settings from OE that we want bundled with the WAB
|
|
for (i=0; i<ARRAYSIZE(OERegDel); i++)
|
|
{
|
|
(*si.pfnRegRestore)(NULL, NULL, hkeyOEBak, OERegDel[i].pszRoot, OERegDel[i].pszSub,
|
|
OERegDel[i].pszValue, ARSR_RESTORE | ARSR_REMOVREGBKDATA | ARSR_NOMESSAGES);
|
|
}
|
|
|
|
if (VER_PLATFORM_WIN32_WINDOWS != si.osv.dwPlatformId)
|
|
RegCloseKey(hkeyOEBak);
|
|
}
|
|
|
|
if (NULL != hkeyWABBak)
|
|
{
|
|
|
|
// Remove settings from WAB that we want bundled with OE
|
|
for (i=0; i<ARRAYSIZE(WABRegDel); i++)
|
|
{
|
|
(*si.pfnRegRestore)(NULL, NULL, hkeyWABBak, WABRegDel[i].pszRoot, WABRegDel[i].pszSub,
|
|
WABRegDel[i].pszValue, ARSR_RESTORE | ARSR_REMOVREGBKDATA | ARSR_NOMESSAGES);
|
|
}
|
|
|
|
if (VER_PLATFORM_WIN32_WINDOWS != si.osv.dwPlatformId)
|
|
RegCloseKey(hkeyWABBak);
|
|
}
|
|
|
|
// If v1 or v1.1 preceded Beta1, restore reg settings that Beta1 deleted so we can roll them
|
|
SETUPVER svPrev;
|
|
GetVerInfo(NULL, &svPrev);
|
|
if (VER_1_0 == svPrev || VER_1_1 == svPrev)
|
|
{
|
|
// Restore IMN reg
|
|
wnsprintf(szTemp, ARRAYSIZE(szTemp), c_szFileEntryFmt, si.szInfDir, si.pszInfFile);
|
|
(*si.pfnRunSetup)(NULL, szTemp, (VER_1_1 == svPrev ? c_szRestoreV1WithWAB : c_szRestoreV1),
|
|
si.szInfDir, si.szAppName, NULL, RSC_FLAG_INF | RSC_FLAG_NGCONV | OE_QUIET, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
RegCloseKey(hkeyWAB);
|
|
}
|
|
RegCloseKey(hkeyOE);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
LOG("Repair attempt complete.");
|
|
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: RespectRedistMode()
|
|
|
|
SYNOPSIS: Sees if IE is installing in redist mode, and persists
|
|
state so per-user install stubs can respect it
|
|
|
|
********************************************************************/
|
|
void RespectRedistMode()
|
|
{
|
|
HKEY hkey;
|
|
BOOL fRedistMode = FALSE;
|
|
DWORD dwDisp;
|
|
DWORD dwInstallMode = 0;
|
|
DWORD dwType;
|
|
DWORD cb;
|
|
|
|
// Is IE Setup running in redist mode, /x or /x:1?
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szIESetupKey, 0, KEY_READ, &hkey))
|
|
{
|
|
cb = sizeof(dwInstallMode);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szIEInstallMode, 0, &dwType, (LPBYTE)&dwInstallMode, &cb))
|
|
{
|
|
if (REG_DWORD == dwType)
|
|
fRedistMode = ((REDIST_REMOVELINKS | REDIST_DONT_TAKE_ASSOCIATION) & dwInstallMode) > 0;
|
|
else
|
|
AssertSz(FALSE, "IE has changed the encoding of their redist mode flag, ignoring");
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
// Let setup know which mode to run in
|
|
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, si.pszVerInfo, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, &dwDisp))
|
|
{
|
|
if (fRedistMode)
|
|
{
|
|
// Our setup only has one redist mode
|
|
dwInstallMode = 1;
|
|
RegSetValueEx(hkey, c_szIEInstallMode, 0, REG_DWORD, (LPBYTE)&dwInstallMode, sizeof(dwInstallMode));
|
|
}
|
|
else
|
|
{
|
|
RegDeleteValue(hkey, c_szIEInstallMode);
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: FDependenciesPresent
|
|
|
|
********************************************************************/
|
|
BOOL FDependenciesPresent(BOOL fPerm)
|
|
{
|
|
BOOL fPresent = FALSE;
|
|
TCHAR szOE[MAX_PATH];
|
|
TCHAR szCommonSys[MAX_PATH];
|
|
TCHAR szTemp[MAX_PATH];
|
|
REPAIRINFO *pRI;
|
|
int n, i;
|
|
HINSTANCE hInst;
|
|
|
|
if (VER_PLATFORM_WIN32_NT == si.osv.dwPlatformId)
|
|
{
|
|
LOG("Avoiding run-time dependency check as we are on NT. Reboot will be required.");
|
|
return FALSE;
|
|
}
|
|
|
|
LOG("Verifying run-time dependencies...");
|
|
|
|
// List of Dlls that we regsvr32 in OE
|
|
const REPAIRINFO OEDlls[] = {
|
|
{"inetcomm.dll", si.szSysDir}, {"msoe.dll", szOE}, {"oeimport.dll", szOE}};
|
|
|
|
// List of Dlls that we regsvr32 in WAB
|
|
const REPAIRINFO WABDlls[] = {
|
|
{"msoeacct.dll", si.szSysDir}, {"wab32.dll", szCommonSys}, {"wabfind.dll", szOE}, {"wabimp.dll", szOE}};
|
|
|
|
// List of Dlls that we regsvr32 permanently in OE
|
|
const REPAIRINFO OEDllsPerm[] = {
|
|
{"directdb.dll", szCommonSys}, {"oemiglib.dll", szOE}};
|
|
|
|
// List of Dlls that we regsvr32 permanently in WAB
|
|
//const REPAIRINFO WABDllsPerm[] = {};
|
|
|
|
|
|
switch (si.saApp)
|
|
{
|
|
case APP_OE:
|
|
if (fPerm)
|
|
{
|
|
// Need OE dir and common sys dir for OEDllsPerm
|
|
if (3 == GetDirNames(1 | 2, szOE, szCommonSys, NULL, NULL))
|
|
{
|
|
pRI = (REPAIRINFO*)OEDllsPerm;
|
|
n = ARRAYSIZE(OEDllsPerm);
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Only need OE dir for OEDlls
|
|
if (1 == GetDirNames(1, szOE, NULL, NULL, NULL))
|
|
{
|
|
pRI = (REPAIRINFO*)OEDlls;
|
|
n = ARRAYSIZE(OEDlls);
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case APP_WAB:
|
|
if (fPerm)
|
|
{
|
|
//pRI = (REPAIRINFO*)OEDllsPerm;
|
|
//n = ARRAYSIZE(OEDllsPerm);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (3 == GetDirNames(1 | 2, szOE, szCommonSys, NULL, NULL))
|
|
{
|
|
pRI = (REPAIRINFO*)WABDlls;
|
|
n = ARRAYSIZE(WABDlls);
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Assert(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
fPresent = TRUE;
|
|
|
|
for (i = 0; fPresent && (i < n); i++)
|
|
{
|
|
Assert(*(pRI[i].pszDir));
|
|
Assert(*(pRI[i].pszFile));
|
|
|
|
wnsprintf(szTemp, ARRAYSIZE(szTemp), c_szFileEntryFmt, pRI[i].pszDir, pRI[i].pszFile);
|
|
if (hInst = LoadLibrary(szTemp))
|
|
FreeLibrary(hInst);
|
|
else
|
|
{
|
|
LOG("Unable to load ");
|
|
LOG2(szTemp);
|
|
LOG("Reboot required.");
|
|
fPresent = FALSE;
|
|
}
|
|
}
|
|
|
|
return fPresent;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: UpdateStubInfo
|
|
|
|
********************************************************************/
|
|
void UpdateStubInfo(BOOL fInstall)
|
|
{
|
|
LPCTSTR pszGUID;
|
|
HKEY hkeySrcRoot, hkeySrc, hkeyDestRoot, hkeyDest;
|
|
DWORD cb, dwType;
|
|
TCHAR szTemp[MAX_PATH];
|
|
|
|
switch (si.saApp)
|
|
{
|
|
case APP_OE:
|
|
pszGUID = c_szOEGUID;
|
|
break;
|
|
case APP_WAB:
|
|
pszGUID = c_szWABGUID;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if (fInstall)
|
|
{
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegASetup, 0, KEY_READ, &hkeySrcRoot))
|
|
{
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(hkeySrcRoot, pszGUID, 0, KEY_QUERY_VALUE, &hkeySrc))
|
|
{
|
|
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, c_szRegASetup, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkeyDestRoot, &dwType))
|
|
{
|
|
if (ERROR_SUCCESS == RegCreateKeyEx(hkeyDestRoot, pszGUID, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkeyDest, &dwType))
|
|
{
|
|
// Copy Version and Locale
|
|
// BUGBUG: Make this extensible via a registry list of values to copy
|
|
cb = sizeof(szTemp);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkeySrc, c_szValueVersion, 0, &dwType, (LPBYTE)szTemp, &cb))
|
|
RegSetValueEx(hkeyDest, c_szValueVersion, 0, dwType, (LPBYTE)szTemp, cb);
|
|
cb = sizeof(szTemp);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkeySrc, c_szLocale, 0, &dwType, (LPBYTE)szTemp, &cb))
|
|
RegSetValueEx(hkeyDest, c_szLocale, 0, dwType, (LPBYTE)szTemp, cb);
|
|
|
|
RegCloseKey(hkeyDest);
|
|
}
|
|
RegCloseKey(hkeyDestRoot);
|
|
}
|
|
RegCloseKey(hkeySrc);
|
|
}
|
|
RegCloseKey(hkeySrcRoot);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegASetup, 0, KEY_WRITE | KEY_READ, &hkeyDestRoot))
|
|
{
|
|
RegDeleteKeyRecursive(hkeyDestRoot, pszGUID);
|
|
RegCloseKey(hkeyDestRoot);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: LaunchINFSectionExWorks
|
|
|
|
SYNOPSIS: IE 5.0 has a bug in which LaunchINFSectionEx does not
|
|
work properly (it can return S_OK when files are in
|
|
use). IE backed out my fix as it broke the 12 lang
|
|
packs. This should be fixed soon though. If we
|
|
ship 5.0 with OSR we can just tweak the INF to turn
|
|
on the correct behaviour.
|
|
|
|
********************************************************************/
|
|
BOOL LaunchINFSectionExWorks()
|
|
{
|
|
HKEY hkey;
|
|
DWORD dw=0, cb;
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, si.pszVerInfo, 0, KEY_QUERY_VALUE, &hkey))
|
|
{
|
|
cb = sizeof(dw);
|
|
RegQueryValueEx(hkey, c_szLaunchWorks, 0, NULL, (LPBYTE)&dw, &cb);
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
return !!dw;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: InstallMachine
|
|
|
|
********************************************************************/
|
|
HRESULT InstallMachine()
|
|
{
|
|
TCHAR szInfFile[MAX_PATH], szArgs[MAX_PATH * 2];
|
|
SETUPVER svPrevVer;
|
|
BOOL fNeedReboot = FALSE;
|
|
BOOL fLaunchEx;
|
|
HRESULT hrT;
|
|
|
|
// Update version info for previous ver
|
|
HandleVersionInfo(FALSE);
|
|
|
|
if (CALLER_IE == si.caller)
|
|
{
|
|
// See if IE is installing in redist mode
|
|
// For more info see: http://ie/specs/secure/corpsetup/batchinstall.htm
|
|
RespectRedistMode();
|
|
|
|
// Bug 66967
|
|
// LaunchINFSectionEx for IE 5.0 does not return accurate reboot info
|
|
fLaunchEx = LaunchINFSectionExWorks();
|
|
|
|
// Special case OE5 B1
|
|
if (InterimBuild(&svPrevVer) && VER_5_0_B1 == svPrevVer)
|
|
RepairBeta1Install();
|
|
|
|
// Perform Permanent portion of setup (excluding DLL reg)
|
|
wnsprintf(szInfFile, ARRAYSIZE(szInfFile), c_szPathFileFmt, si.szCurrentDir, si.pszInfFile);
|
|
hrT = (*si.pfnRunSetup)(NULL, szInfFile, c_szMachineInstallSection, si.szCurrentDir, si.szAppName, NULL, RSC_FLAG_INF | RSC_FLAG_NGCONV | OE_QUIET, 0);
|
|
|
|
// See if the file copies need a reboot
|
|
if (!fLaunchEx || (ERROR_SUCCESS_REBOOT_REQUIRED == hrT))
|
|
fNeedReboot = TRUE;
|
|
else
|
|
// See if we are going to need a reboot anyway because our perm dlls won't load
|
|
fNeedReboot = !FDependenciesPresent(TRUE);
|
|
|
|
// Register the Perm dlls keeping in mind whether we'll need a reboot
|
|
(*si.pfnRunSetup)(NULL, szInfFile, c_szRegisterPermOCX, si.szCurrentDir, si.szAppName, NULL, RSC_FLAG_INF | RSC_FLAG_NGCONV | OE_QUIET | (fNeedReboot ? RSC_FLAG_DELAYREGISTEROCX : 0), 0);
|
|
|
|
PreRollable();
|
|
|
|
// Perform Rollable portion of setup (excluding DLL reg)
|
|
wnsprintf(szArgs, ARRAYSIZE(szArgs), c_szLaunchFmt, szInfFile, c_szMachineInstallSectionEx, c_szEmpty, ALINF_BKINSTALL | ALINF_NGCONV | OE_QUIET | (fNeedReboot ? RSC_FLAG_DELAYREGISTEROCX : 0));
|
|
hrT = (*si.pfnLaunchEx)(NULL, NULL, szArgs, 0);
|
|
|
|
// If we've gotten away without needing a reboot so far...
|
|
if (!fNeedReboot)
|
|
{
|
|
// See if the file copies need a reboot
|
|
if (ERROR_SUCCESS_REBOOT_REQUIRED == hrT)
|
|
fNeedReboot = TRUE;
|
|
else
|
|
// See if we are going to need a reboot anyway because our rollable dlls won't load
|
|
fNeedReboot = !FDependenciesPresent(FALSE);
|
|
}
|
|
|
|
// Register OCXs
|
|
(*si.pfnRunSetup)(NULL, szInfFile, c_szRegisterOCX, si.szCurrentDir, si.szAppName, NULL, RSC_FLAG_INF | RSC_FLAG_NGCONV | OE_QUIET | (fNeedReboot ? RSC_FLAG_DELAYREGISTEROCX : 0), 0);
|
|
}
|
|
else
|
|
// We delayed writing the active setup ver so that HandleVersionInfo could sniff it, but must put it in now.
|
|
ApplyActiveSetupVer();
|
|
|
|
// Run any need post setup goo
|
|
RunPostSetup();
|
|
|
|
// Handle setting default handlers
|
|
SetHandlers();
|
|
|
|
// Update version info for current version
|
|
HandleVersionInfo(TRUE);
|
|
|
|
// Run the User stub if we can (don't run per-user goo at the end of NT GUI mode setup)
|
|
if (!fNeedReboot && (CALLER_WINNT != si.caller))
|
|
{
|
|
InstallUser();
|
|
// Ensure stub cleanup will run if they immediately uninstall
|
|
UpdateStubInfo(TRUE);
|
|
return S_OK;
|
|
}
|
|
|
|
return ERROR_SUCCESS_REBOOT_REQUIRED;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: InstallUser
|
|
|
|
********************************************************************/
|
|
void InstallUser()
|
|
{
|
|
TCHAR szInfFile[MAX_PATH];
|
|
|
|
// Move settings under this version's key in the registry
|
|
UpgradeSettings();
|
|
|
|
// Call the UserInstall section of the inf
|
|
wnsprintf(szInfFile, ARRAYSIZE(szInfFile), c_szFileEntryFmt, si.szInfDir, si.pszInfFile);
|
|
|
|
const TCHAR *pszUserInstallSection;
|
|
|
|
// If it's OE and we're on XP SP1 or later, we will let the OEAccess component in shmgrate.exe
|
|
// take care of showing/hiding icons
|
|
if ((0 == lstrcmpi(c_szMsimnInf, si.pszInfFile)) && IsXPSP1OrLater())
|
|
{
|
|
pszUserInstallSection = c_szUserInstallSectionOEOnXPSP1OrLater;
|
|
}
|
|
else
|
|
{
|
|
pszUserInstallSection = c_szUserInstallSection;
|
|
}
|
|
(*si.pfnRunSetup)(NULL, szInfFile, pszUserInstallSection, si.szInfDir, si.szAppName, NULL, RSC_FLAG_INF | OE_QUIET, 0);
|
|
|
|
// Create Desktop, Quick launch and start menu icons
|
|
HandleLinks(TRUE);
|
|
|
|
if (IsXPSP1OrLater())
|
|
{
|
|
TCHAR szCmdLine[MAX_PATH];
|
|
|
|
GetSystemDirectory(szCmdLine, ARRAYSIZE(szCmdLine));
|
|
|
|
DWORD cb = 0;
|
|
PathAddSlash(szCmdLine, &cb);
|
|
|
|
int cch = lstrlen(szCmdLine);
|
|
|
|
StrCpyN(szCmdLine + cch, ("shmgrate.exe"), ARRAYSIZE(szCmdLine) - cch);
|
|
|
|
ShellExecute(NULL, NULL, szCmdLine, TEXT("OCInstallUserConfigOE"), NULL, SW_SHOWDEFAULT);
|
|
}
|
|
}
|