2025-04-27 07:49:33 -04:00

2291 lines
57 KiB
C++

#include "stdafx.h"
#include "userenv.h"
#include "userenvp.h"
#include "shlobj.h"
#include "utils.h"
#include "mddefw.h"
#include "mdkey.h"
#include "wizpages.h"
#include "ocmanage.h"
#include "setupapi.h"
#include "k2suite.h"
#include "ndmgr.h"
#include "mycomput.h"
extern OCMANAGER_ROUTINES gHelperRoutines;
// This function provides StrChr functionality
LPTSTR MyStrChr(LPCTSTR szString, TCHAR tcChar)
{
while (*szString != _T('\0'))
{
if (*szString == tcChar)
return((LPTSTR)szString);
szString++;
}
return(NULL);
}
// This function finds the first non-whitespace
LPTSTR NextNonSpace(LPTSTR szString)
{
while ((*szString == _T(' ')) || (*szString == _T('\t')))
{
if (!*szString)
return(NULL);
*szString++;
}
return(szString);
}
// This function finds the first whitespace
LPTSTR NextSpace(LPTSTR szString)
{
while ((*szString != _T(' ')) && (*szString != _T('\t')) &&
(*szString != _T('\0')))
{
*szString++;
}
return(szString);
}
BOOL ParseInfLineArguments(LPCTSTR szLine, LPTSTR szAttribute, LPTSTR szValue)
{
LPTSTR pEqual, pAttrStart, pValueStart;
TCHAR tcTemp;
pAttrStart = NextNonSpace((LPTSTR)szLine);
if (!pAttrStart)
return(FALSE);
pEqual = MyStrChr(szLine, _T('='));
if (pEqual)
{
// Found equal sign
if (pAttrStart >= pEqual)
return(FALSE);
pValueStart = NextNonSpace(pEqual + 1);
if (pValueStart)
lstrcpy(szValue, pValueStart);
}
else
*szValue = _T('\0');
// Find the end of the attribute name
pValueStart = NextSpace(pAttrStart);
tcTemp = *pValueStart;
*pValueStart = _T('\0');
lstrcpy(szAttribute, pAttrStart);
*pValueStart = tcTemp;
return(TRUE);
}
// This function obtains the root directory of a directory
BOOL GetRootDirectory(LPCTSTR szDirectory, LPTSTR szRootDir, DWORD cbLength)
{
DWORD dwLen = lstrlen(szDirectory);
SetLastError(ERROR_INVALID_PARAMETER);
if (dwLen < 2)
return(FALSE);
if (szDirectory[0] == _T('\\') &&
szDirectory[1] == _T('\\'))
{
LPTSTR lpTemp;
// This is a UNC, get the share name. We find the 4th
// backslash and take everything before that.
lpTemp = MyStrChr(szDirectory + 2, _T('\\'));
if (!lpTemp)
return(FALSE);
lpTemp = MyStrChr(lpTemp + 1, _T('\\'));
if (!lpTemp)
return(FALSE);
// Get how many bytes to copy
dwLen = (DWORD)(lpTemp - szDirectory + 1);
if (cbLength < dwLen)
{
SetLastError(ERROR_MORE_DATA);
return(FALSE);
}
lstrcpyn(szRootDir, szDirectory, dwLen);
}
else
{
if (cbLength < 4)
{
SetLastError(ERROR_MORE_DATA);
return(FALSE);
}
// This is a drive specification
if (szDirectory[1] != _T(':'))
return(FALSE);
if (dwLen == 2)
{
lstrcpy(szRootDir, szDirectory);
lstrcat(szRootDir, _T("\\"));
}
else
{
if (szDirectory[2] != _T('\\'))
return(FALSE);
lstrcpyn(szRootDir, szDirectory, 4);
}
}
return(TRUE);
}
// This function uses a WIN32 function to check for bad directory names
// Hacky, but works :-)
BOOL IsDirectoryLexicallyValid(LPCTSTR szPath)
{
HANDLE hDir;
BOOL fRet = FALSE;
hDir = FindFirstChangeNotification(szPath, FALSE, FILE_NOTIFY_CHANGE_SECURITY);
if (hDir == INVALID_HANDLE_VALUE || hDir == NULL)
{
DWORD dwErr = GetLastError();
}
else
{
fRet = TRUE;
FindCloseChangeNotification(hDir);
}
return(fRet);
}
// This funciton determines if a volume is NTFS
BOOL IsVolumeNtfs(LPCTSTR szDisk)
{
TCHAR szVolume[MAX_PATH];
TCHAR szFileSystem[MAX_PATH];
DWORD lSerial, lMaxLen, lFlags;
if (GetVolumeInformation(szDisk, szVolume, MAX_PATH,
&lSerial, &lMaxLen, &lFlags,
szFileSystem, MAX_PATH))
{
if(!lstrcmpi(szFileSystem, _T("NTFS")))
return(TRUE);
}
return(FALSE);
}
// This funciton determines if a the local machine constains at
// least one NTFS volume
BOOL AnyNtfsVolumesOnLocalMachine(LPTSTR szFirstNtfsVolume)
{
TCHAR szDrives[256];
TCHAR *lpCurrentDrive;
DWORD dwLength, dwType;
*szFirstNtfsVolume = _T('\0');
dwLength = GetLogicalDriveStrings(256, szDrives);
if (dwLength)
{
lpCurrentDrive = szDrives;
while (*lpCurrentDrive != _T('\0'))
{
// Make sure this is not removable media
dwType = GetDriveType(lpCurrentDrive);
if (dwType & DRIVE_FIXED)
{
// Fixed media, see if it is NTFS ...
if (IsVolumeNtfs(lpCurrentDrive))
{
lstrcpy(szFirstNtfsVolume, lpCurrentDrive);
return(TRUE);
}
}
// Next drive
lpCurrentDrive += (lstrlen(lpCurrentDrive) + 1);
}
}
return(FALSE);
}
DWORD GetUnattendedMode(HANDLE hUnattended, LPCTSTR szSubcomponent)
{
BOOL b = FALSE;
TCHAR szLine[1024];
DWORD dwMode = SubcompUseOcManagerDefault;
CString csMsg;
csMsg = _T("GetUnattendedMode ");
csMsg += szSubcomponent;
csMsg += _T("\n");
DebugOutput((LPCTSTR)csMsg);
// Try to get the line of interest
if (hUnattended && (hUnattended != INVALID_HANDLE_VALUE))
{
b = SetupGetLineText(NULL, hUnattended, _T("Components"),
szSubcomponent, szLine, sizeof(szLine), NULL);
if (b)
{
csMsg = szSubcomponent;
csMsg += _T(" = ");
csMsg += szLine;
csMsg += _T("\n");
DebugOutput((LPCTSTR)csMsg);
// Parse the line
if (!lstrcmpi(szLine, _T("on")))
{
dwMode = SubcompOn;
}
else if (!lstrcmpi(szLine, _T("off")))
{
dwMode = SubcompOff;
}
else if (!lstrcmpi(szLine, _T("default")))
{
dwMode = SubcompUseOcManagerDefault;
}
}
else
DebugOutput(_T("SetupGetLineText failed.\n"));
}
return(dwMode);
}
DWORD GetUnattendedModeFromSetupMode(
HANDLE hUnattended,
DWORD dwComponent,
LPCTSTR szSubcomponent)
{
BOOL b = FALSE;
TCHAR szProperty[64];
TCHAR szLine[1024];
DWORD dwMode = SubcompUseOcManagerDefault;
DWORD dwSetupMode;
DebugOutput(_T("GetUnattendedModeFromSetupMode %s"), szSubcomponent);
// Try to get the line of interest
if (hUnattended && (hUnattended != INVALID_HANDLE_VALUE))
{
dwSetupMode = GetIMSSetupMode();
switch (dwSetupMode)
{
case IIS_SETUPMODE_MINIMUM:
case IIS_SETUPMODE_TYPICAL:
case IIS_SETUPMODE_CUSTOM:
// One of the fresh modes
lstrcpy(szProperty, _T("FreshMode"));
break;
case IIS_SETUPMODE_UPGRADEONLY:
case IIS_SETUPMODE_ADDEXTRACOMPS:
// One of the upgrade modes
lstrcpy(szProperty, _T("UpgradeMode"));
break;
case IIS_SETUPMODE_ADDREMOVE:
case IIS_SETUPMODE_REINSTALL:
case IIS_SETUPMODE_REMOVEALL:
// One of the maintenance modes
lstrcpy(szProperty, _T("MaintanenceMode"));
break;
default:
// Error! Use defaults
return(SubcompUseOcManagerDefault);
}
// Get the specified line
b = SetupGetLineText(
NULL,
hUnattended,
_T("Global"),
szProperty,
szLine,
sizeof(szLine),
NULL);
if (b)
{
DWORD dwOriginalMode;
DebugOutput(_T("%s = %s\n"), szProperty, szLine);
// See which setup mode we will end up with
if (!lstrcmpi(szLine, _T("Minimal")))
dwSetupMode = IIS_SETUPMODE_MINIMUM;
else if (!lstrcmpi(szLine, _T("Typical")))
dwSetupMode = IIS_SETUPMODE_TYPICAL;
else if (!lstrcmpi(szLine, _T("Custom")))
dwSetupMode = IIS_SETUPMODE_CUSTOM;
else if (!lstrcmpi(szLine, _T("AddRemove")))
dwSetupMode = IIS_SETUPMODE_ADDREMOVE;
else if (!lstrcmpi(szLine, _T("RemoveAll")))
dwSetupMode = IIS_SETUPMODE_REMOVEALL;
else if (!lstrcmpi(szLine, _T("UpgradeOnly")))
dwSetupMode = IIS_SETUPMODE_UPGRADEONLY;
else if (!lstrcmpi(szLine, _T("AddExtraComps")))
dwSetupMode = IIS_SETUPMODE_ADDEXTRACOMPS;
else
return(SubcompUseOcManagerDefault);
// Get the custom unattended setting
dwMode = GetUnattendedMode(hUnattended, szSubcomponent);
// Do the right thing based on the setup mode
SetIMSSetupMode(dwSetupMode);
switch (dwSetupMode)
{
case IIS_SETUPMODE_MINIMUM:
case IIS_SETUPMODE_TYPICAL:
// Minimum & typical means the same:
// Install all for SMTP, none for NNTP
DebugOutput(_T("Unattended mode is MINIMUM/TYPICAL"));
if (dwComponent == MC_IMS)
dwMode = SubcompOn;
else
dwMode = SubcompOff;
break;
case IIS_SETUPMODE_CUSTOM:
// For custom we use the custom setting
DebugOutput(_T("Unattended mode is CUSTOM"));
break;
case IIS_SETUPMODE_UPGRADEONLY:
// Return the original state
DebugOutput(_T("Unattended mode is UPGRADEONLY"));
dwMode = gHelperRoutines.QuerySelectionState(
gHelperRoutines.OcManagerContext,
szSubcomponent,
OCSELSTATETYPE_ORIGINAL) ? SubcompOn : SubcompOff;
break;
case IIS_SETUPMODE_ADDEXTRACOMPS:
// Turn it on only if the old state is off and the
// custom state is on
DebugOutput(_T("Unattended mode is ADDEXTRACOMPS"));
dwOriginalMode = gHelperRoutines.QuerySelectionState(
gHelperRoutines.OcManagerContext,
szSubcomponent,
OCSELSTATETYPE_ORIGINAL) ? SubcompOn : SubcompOff;
if (dwOriginalMode == SubcompOff &&
dwMode == SubcompOn)
dwMode = SubcompOn;
else
dwMode = dwOriginalMode;
break;
case IIS_SETUPMODE_ADDREMOVE:
// Return the custom setting
DebugOutput(_T("Unattended mode is ADDREMOVE"));
break;
case IIS_SETUPMODE_REMOVEALL:
// Kill everything
DebugOutput(_T("Unattended mode is REMOVEALL"));
dwMode = SubcompOff;
break;
}
DebugOutput(_T("Unattended state for %s is %s"),
szSubcomponent,
(dwMode == SubcompOn)?_T("ON"):_T("OFF"));
}
else
DebugOutput(_T("SetupGetLineText failed (%u).\n"), GetLastError());
}
return(dwMode);
}
BOOL DetectExistingSmtpServers()
{
// Detect other mail servers
CRegKey regMachine = HKEY_LOCAL_MACHINE;
// System\CurrentControlSet\Services\MsExchangeIMC\Parameters
CRegKey regSMTPParam( regMachine, REG_EXCHANGEIMCPARAMETERS, KEY_READ );
if ((HKEY) regSMTPParam )
{
CString csCaption;
DebugOutput(_T("IMC detected, suppressing SMTP"));
if (!theApp.m_fIsUnattended && !theApp.m_fNTGuiMode)
{
MyLoadString(IDS_MESSAGEBOX_TEXT, csCaption);
PopupOkMessageBox(IDS_SUPPRESS_SMTP, csCaption);
}
return(TRUE);
}
DebugOutput(_T("No other SMTP servers detected, installing IMS."));
return(FALSE);
}
BOOL DetectExistingIISADMIN()
{
//
// Detect is IISADMIN service exists
//
// This is to make sure we don't do any metabase operation if
// IISADMIN doesn't exists, especially in the uninstall cases.
//
DWORD dwStatus = 0;
dwStatus = InetQueryServiceStatus(SZ_MD_SERVICENAME);
if (0 == dwStatus)
{
// some kind of error occur during InetQueryServiceStatus.
DebugOutput(_T("DetectExistingIISADMIN() return FALSE\n"));
return (FALSE);
}
return(TRUE);
}
BOOL InsertSetupString( LPCSTR REG_PARAMETERS )
{
// set up registry values
CRegKey regMachine = HKEY_LOCAL_MACHINE;
// System\CurrentControlSet\Services\NNTPSVC\Parameters
CRegKey regParam( (LPCTSTR) REG_PARAMETERS, regMachine );
if ((HKEY) regParam) {
regParam.SetValue( _T("MajorVersion"), (DWORD)STAXNT5MAJORVERSION );
regParam.SetValue( _T("MinorVersion"), (DWORD)STAXNT5MINORVERSION );
regParam.SetValue( _T("InstallPath"), theApp.m_csPathInetsrv );
switch (theApp.m_eNTOSType) {
case OT_NTW:
regParam.SetValue( _T("SetupString"), REG_SETUP_STRING_NT5WKSB3 );
break;
default:
_ASSERT(!"Unknown OS type");
// Fall through
case OT_NTS:
case OT_PDC_OR_BDC:
case OT_PDC:
case OT_BDC:
regParam.SetValue( _T("SetupString"), REG_SETUP_STRING_NT5SRVB3 );
break;
}
}
return TRUE;
}
// Scans a multi-sz and finds the first occurrence of the
// specified string
LPTSTR ScanMultiSzForSz(LPTSTR szMultiSz, LPTSTR szSz)
{
LPTSTR lpTemp = szMultiSz;
do
{
if (!lstrcmpi(lpTemp, szSz))
return(lpTemp);
lpTemp += lstrlen(lpTemp);
lpTemp++;
} while (*lpTemp != _T('\0'));
return(NULL);
}
// Removes the said string from a MultiSz
// This places a lot of faith in the caller!
void RemoveSzFromMultiSz(LPTSTR szSz)
{
LPTSTR lpScan = szSz;
TCHAR tcLastChar;
lpScan += lstrlen(szSz);
lpScan++;
tcLastChar = _T('x');
while ((tcLastChar != _T('\0')) ||
(*lpScan != _T('\0')))
{
tcLastChar = *lpScan;
*szSz++ = *lpScan++;
}
*szSz++ = _T('\0');
// Properly terminate it if it's the last one
if (*lpScan == _T('\0'))
*szSz = _T('\0');
}
// This walks the multi-sz and returns a pointer between
// the last string of a multi-sz and the second terminating
// NULL
LPTSTR GetEndOfMultiSz(LPTSTR szMultiSz)
{
LPTSTR lpTemp = szMultiSz;
do
{
lpTemp += lstrlen(lpTemp);
lpTemp++;
} while (*lpTemp != _T('\0'));
return(lpTemp);
}
// This appends a string to the end of a multi-sz
// The buffer must be long enough
BOOL AppendSzToMultiSz(LPTSTR szMultiSz, LPTSTR szSz, DWORD dwMaxSize)
{
LPTSTR szTemp = szMultiSz;
DWORD dwLength = lstrlen(szSz);
// If the string is empty, do not append!
if (*szMultiSz == _T('\0') &&
*(szMultiSz + 1) == _T('\0'))
szTemp = szMultiSz;
else
{
szTemp = GetEndOfMultiSz(szMultiSz);
dwLength += (DWORD)(szTemp - szMultiSz);
}
if (dwLength >= dwMaxSize)
return(FALSE);
lstrcpy(szTemp, szSz);
szMultiSz += dwLength;
*szMultiSz = _T('\0');
*(szMultiSz + 1) = _T('\0');
return(TRUE);
}
BOOL AddServiceToDispatchList(LPTSTR szServiceName)
{
TCHAR szMultiSz[4096];
DWORD dwSize = 4096;
CRegKey RegInetInfo(REG_INETINFOPARAMETERS, HKEY_LOCAL_MACHINE);
if ((HKEY)RegInetInfo)
{
// Default to empty string if not exists
szMultiSz[0] = _T('\0');
szMultiSz[1] = _T('\0');
if (RegInetInfo.QueryValue(SZ_INETINFODISPATCH, szMultiSz, dwSize) == NO_ERROR)
{
// Walk the list to see if the value is already there
if (ScanMultiSzForSz(szMultiSz, szServiceName))
return(TRUE);
}
// Create the value and add it to the list
if (!AppendSzToMultiSz(szMultiSz, szServiceName, dwSize))
return(FALSE);
// Get the size of the new Multi-sz
dwSize = (DWORD)(GetEndOfMultiSz(szMultiSz) - szMultiSz) + 1;
// Write the value back to the registry
if (RegInetInfo.SetValue(SZ_INETINFODISPATCH, szMultiSz, dwSize * (DWORD) sizeof(TCHAR)) == NO_ERROR)
return(TRUE);
}
// If the InetInfo key is not here, there isn't much we can do ...
return(FALSE);
}
BOOL RemoveServiceFromDispatchList(LPTSTR szServiceName)
{
TCHAR szMultiSz[4096];
DWORD dwSize = 4096;
LPTSTR szTemp;
BOOL fFound = FALSE;
CRegKey RegInetInfo(HKEY_LOCAL_MACHINE, REG_INETINFOPARAMETERS);
if ((HKEY)RegInetInfo)
{
if (RegInetInfo.QueryValue(SZ_INETINFODISPATCH, szMultiSz, dwSize) == NO_ERROR)
{
// Walk the list to see if the value is already there
while (szTemp = ScanMultiSzForSz(szMultiSz, szServiceName))
{
RemoveSzFromMultiSz(szTemp);
fFound = TRUE;
}
}
// Write the value back to the registry if necessary, note we
// will indicate success if the string is not found
if (!fFound)
return(TRUE);
// Get the size of the new Multi-sz
dwSize = (DWORD)(GetEndOfMultiSz(szMultiSz) - szMultiSz) + 1;
// Write the value back to the registry
if (RegInetInfo.SetValue(SZ_INETINFODISPATCH, szMultiSz, dwSize * (DWORD) sizeof(TCHAR)) == NO_ERROR)
return(TRUE);
}
// If the InetInfo key is not here, there isn't much we can do ...
return(FALSE);
}
void GetIISProgramGroup(CString &csGroupName, BOOL fIsMcisGroup)
{
TCHAR szName[_MAX_PATH];
CString csTempName;
UINT uType, uSize;
if (fIsMcisGroup) {
csGroupName = "";
} else {
// Get the NT program group name from the private data
uSize = _MAX_PATH * sizeof(TCHAR);
#if 0
//11/30/98 - Don't even try to do this, just get the default
if ((gHelperRoutines.GetPrivateData(gHelperRoutines.OcManagerContext,
_T("iis"),
_T("NTProgramGroup"),
(LPVOID)szName,
&uSize,
&uType) != NO_ERROR) ||
(uType != REG_SZ))
#endif
{
// We use the default group name
MyLoadString(IDS_DEFAULT_NT_PROGRAM_GROUP, csTempName);
lstrcpy(szName, csTempName.GetBuffer(_MAX_PATH));
csTempName.ReleaseBuffer();
}
csGroupName = szName;
csGroupName += _T("\\");
// Get the IIS program group name from the private data
uSize = _MAX_PATH * sizeof(TCHAR);
#if 0
//11/30/98 - Don't even try to do this, just get the default
if ((gHelperRoutines.GetPrivateData(gHelperRoutines.OcManagerContext,
_T("iis"),
_T("IISProgramGroup"),
(LPVOID)szName,
&uSize,
&uType) != NO_ERROR) ||
(uType != REG_SZ))
#endif
{
// We use the default group name
MyLoadString(IDS_DEFAULT_IIS_PROGRAM_GROUP, csTempName);
lstrcpy(szName, csTempName.GetBuffer(_MAX_PATH));
csTempName.ReleaseBuffer();
}
csGroupName += szName;
}
}
void MyGetGroupPath(LPCTSTR szGroupName, LPTSTR szPath);
BOOL GetFullPathToProgramGroup(DWORD dwMainComponent, CString &csGroupName, BOOL fIsMcisGroup)
{
// add items to the program group
CString csTemp;
TCHAR szPath[MAX_PATH];
// Get the program group name from the private data
GetIISProgramGroup(csTemp, fIsMcisGroup);
// Get the system path to this menu item
MyGetGroupPath((LPCTSTR)csTemp, szPath);
csGroupName = szPath;
// Load up the resource string for the group
if (fIsMcisGroup)
MyLoadString(IDS_PROGGROUP_MCIS_MAIL_AND_NEWS, csTemp);
else
MyLoadString(dwMainComponent == MC_IMS?IDS_PROGGROUP_MAIL:IDS_PROGGROUP_NEWS, csTemp);
// Build the program group
csGroupName += csTemp;
DebugOutput(_T("Program group loaded: %s"), (LPCTSTR)csGroupName);
return(TRUE);
}
BOOL GetFullPathToAdminGroup(DWORD dwMainComponent, CString &csGroupName)
{
// add items to the program group
CString csTemp;
TCHAR szPath[MAX_PATH];
// Get the program group name from the private data
MyLoadString( IDS_PROGGROUP_ADMINTOOLS, csTemp );
// Get the system path to this menu item
MyGetGroupPath((LPCTSTR)csTemp, szPath);
csGroupName = szPath;
DebugOutput(_T("Program group loaded: %s"), (LPCTSTR)csGroupName);
return(TRUE);
}
BOOL RemoveProgramGroupIfEmpty(DWORD dwMainComponent, BOOL fIsMcisGroup)
{
// add items to the program group
CString csGroupName;
CString csTemp;
TCHAR szPath[MAX_PATH];
BOOL fResult;
// Get the program group name from the private data
GetIISProgramGroup(csTemp, fIsMcisGroup);
// Get the system path to this menu item
MyGetGroupPath((LPCTSTR)csTemp, szPath);
csGroupName = szPath;
// Load up the resource string for the group
if (fIsMcisGroup)
MyLoadString(IDS_PROGGROUP_MCIS_MAIL_AND_NEWS, csTemp);
else
MyLoadString(dwMainComponent == MC_IMS?IDS_PROGGROUP_MAIL:IDS_PROGGROUP_NEWS, csTemp);
// Build the program group
csGroupName += csTemp;
DebugOutput(_T("Removing Program group: %s"), (LPCTSTR)csGroupName);
fResult = RemoveDirectory((LPCTSTR)csGroupName);
if (fResult && fIsMcisGroup)
{
SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, (LPCTSTR)csGroupName, 0);
csGroupName = szPath;
MyLoadString(IDS_MCIS_2_0, csTemp);
csGroupName += csTemp;
fResult = RemoveDirectory((LPCTSTR)csGroupName);
}
if (fResult)
{
SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, (LPCTSTR)csGroupName, 0);
}
return(fResult);
}
BOOL CreateInternetShortcut(DWORD dwMainComponent, int dwDisplayNameId, int dwUrlId, BOOL fIsMcisGroup)
{
CString csItemPath;
CString csDisplayName;
CString csUrl;
HANDLE hShortcut;
DWORD dwLength, dwWritten;
char szBuffer[1000];
char szContent[1024];
BOOL fRet = FALSE;
MyLoadString(dwDisplayNameId, csDisplayName);
MyLoadString(dwUrlId, csUrl);
// Build the full path to the program link
GetFullPathToProgramGroup(dwMainComponent, csItemPath, fIsMcisGroup);
// Make sure our directory is there
CreateLayerDirectory(csItemPath);
csItemPath += _T("\\");
csItemPath += csDisplayName;
csItemPath += _T(".url");
DebugOutput(_T("Creating shortcut file: %s"), (LPCTSTR)csItemPath);
// Create the file in the directory
hShortcut = CreateFile((LPCTSTR)csItemPath,
GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (hShortcut == INVALID_HANDLE_VALUE)
{
DebugOutput(_T("CreateFile failed with error %u\n"), GetLastError());
return(fRet);
}
// Convert the Unicode string to ANSI
if (WideCharToMultiByte(CP_ACP, 0,
(LPCTSTR)csUrl,
-1,
szBuffer,
sizeof(szBuffer),
NULL, NULL))
{
dwLength = sprintf(szContent, "[InternetShortcut]\nURL=http://localhost/%s\n", szBuffer);
DebugOutput(_T(" Shortcut: %s"), (LPCTSTR)csUrl);
if (dwLength)
{
if (WriteFile(hShortcut, szContent, dwLength, &dwWritten, NULL) &&
(dwWritten == dwLength))
{
SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, (LPCTSTR)csItemPath, 0);
fRet = TRUE;
}
}
}
else
{
DebugOutput(_T("WideCharToMultiByte failed with error %u\n"), GetLastError());
}
CloseHandle(hShortcut);
return(fRet);
}
#if 0 // Dead code
BOOL CreateNt5InternetShortcut(DWORD dwMainComponent, int dwDisplayNameId, int dwUrlId)
{
CString csItemPath;
CString csDisplayName;
CString csUrl;
HANDLE hShortcut;
DWORD dwLength, dwWritten;
char szBuffer[1000];
char szContent[1024];
BOOL fRet = FALSE;
MyLoadString(dwDisplayNameId, csDisplayName);
MyLoadString(dwUrlId, csUrl);
// Build the full path to the program link
GetFullPathToAdminGroup(dwMainComponent, csItemPath);
// Make sure our directory is there
CreateLayerDirectory(csItemPath);
csItemPath += _T("\\");
csItemPath += csDisplayName;
csItemPath += _T(".url");
DebugOutput(_T("Creating shortcut file: %s"), (LPCTSTR)csItemPath);
// Create the file in the directory
hShortcut = CreateFile((LPCTSTR)csItemPath,
GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (hShortcut == INVALID_HANDLE_VALUE)
{
DebugOutput(_T("CreateFile failed with error %u\n"), GetLastError());
return(fRet);
}
// Convert the Unicode string to ANSI
if (WideCharToMultiByte(CP_ACP, 0,
(LPCTSTR)csUrl,
-1,
szBuffer,
sizeof(szBuffer),
NULL, NULL))
{
dwLength = sprintf(szContent, "[InternetShortcut]\nURL=http://localhost/%s\n", szBuffer);
DebugOutput(_T(" Shortcut: %s"), (LPCTSTR)csUrl);
if (dwLength)
{
if (WriteFile(hShortcut, szContent, dwLength, &dwWritten, NULL) &&
(dwWritten == dwLength))
{
SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, (LPCTSTR)csItemPath, 0);
fRet = TRUE;
}
}
}
else
{
DebugOutput(_T("WideCharToMultiByte failed with error %u\n"), GetLastError());
}
CloseHandle(hShortcut);
return(fRet);
}
#endif
BOOL RemoveInternetShortcut(DWORD dwMainComponent, int dwDisplayNameId, BOOL fIsMcisGroup)
{
CString csItemPath;
CString csDisplayName;
MyLoadString(dwDisplayNameId, csDisplayName);
// Build the full path to the program link
GetFullPathToProgramGroup(dwMainComponent, csItemPath, fIsMcisGroup);
csItemPath += _T("\\");
csItemPath += csDisplayName;
csItemPath += _T(".url");
DebugOutput(_T("Removing shortcut file: %s"), (LPCTSTR)csItemPath);
DeleteFile((LPCTSTR)csItemPath);
SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, (LPCTSTR)csItemPath, 0);
RemoveProgramGroupIfEmpty(dwMainComponent, fIsMcisGroup);
return(TRUE);
}
BOOL RemoveNt5InternetShortcut(DWORD dwMainComponent, int dwDisplayNameId)
{
CString csItemPath;
CString csDisplayName;
MyLoadString(dwDisplayNameId, csDisplayName);
// Build the full path to the program link
GetFullPathToAdminGroup(dwMainComponent, csItemPath);
csItemPath += _T("\\");
csItemPath += csDisplayName;
csItemPath += _T(".url");
DebugOutput(_T("Removing shortcut file: %s"), (LPCTSTR)csItemPath);
DeleteFile((LPCTSTR)csItemPath);
SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, (LPCTSTR)csItemPath, 0);
#if 0
RemoveProgramGroupIfEmpty(dwMainComponent,FALSE);
#endif
return(TRUE);
}
BOOL RemoveMCIS10MailProgramGroup()
{
CString csGroupName;
CString csNiceName;
MyLoadString(IDS_PROGGROUP_MCIS10_MAIL, csGroupName);
MyLoadString(IDS_PROGITEM_MCIS10_MAIL_STARTPAGE, csNiceName);
MyDeleteItem(csGroupName, csNiceName);
MyLoadString(IDS_PROGITEM_MCIS10_MAIL_WEBADMIN, csNiceName);
MyDeleteItemEx(csGroupName, csNiceName);
return(TRUE);
}
BOOL RemoveMCIS10NewsProgramGroup()
{
CString csGroupName;
CString csNiceName;
// BINLIN:
// BUGBUG: need to figure out how to get
// the old MCIS 1.0 program group path
MyLoadString(IDS_PROGGROUP_MCIS10_NEWS, csGroupName);
MyLoadString(IDS_PROGITEM_MCIS10_NEWS_STARTPAGE, csNiceName);
MyDeleteItem(csGroupName, csNiceName);
MyLoadString(IDS_PROGITEM_MCIS10_NEWS_WEBADMIN, csNiceName);
MyDeleteItemEx(csGroupName, csNiceName);
return(TRUE);
}
BOOL CreateUninstallEntries(LPCTSTR szInfFile, LPCTSTR szDisplayName)
{
// We have one or more components installed, so we
// will create the Add/Remove options in the control panel
CString csUninstall;
CString AddRemoveRegPath = REG_UNINSTALL;
AddRemoveRegPath += _T("\\");
AddRemoveRegPath += szInfFile;
csUninstall = theApp.m_csSysDir + _T("\\sysocmgr.exe /i:");
csUninstall += theApp.m_csSysDir;
csUninstall += _T("\\setup\\");
csUninstall += szInfFile;
CRegKey regAddRemove(AddRemoveRegPath, HKEY_LOCAL_MACHINE);
if ( (HKEY)regAddRemove )
{
regAddRemove.SetValue( _T("DisplayName"), szDisplayName );
regAddRemove.SetValue( _T("UninstallString"), csUninstall );
}
else
return(FALSE);
return(TRUE);
}
BOOL RemoveUninstallEntries(LPCTSTR szInfFile)
{
// All components are removed, we will have to remove
// the Add/Remove option from the control panel
CRegKey regUninstall( HKEY_LOCAL_MACHINE, REG_UNINSTALL);
if ((HKEY)regUninstall)
regUninstall.DeleteTree(szInfFile);
else
return(FALSE);
return(TRUE);
}
void SetProductName()
{
// The product name is rather complicated ...
CString csProdName, csAppName;
if (theApp.m_hInfHandle[MC_IMS] && theApp.m_hInfHandle[MC_INS])
{
MyLoadString(IDS_MAIL_AND_NEWS, csProdName);
MyLoadString(IDS_MAIL_AND_NEWS_SETUP, csAppName);
}
else if (theApp.m_hInfHandle[MC_IMS])
{
// NT5 - For SMTP, use the default K2 name
if (theApp.m_fIsMcis)
{
MyLoadString(IDS_MCIS_MAIL_ONLY, csProdName);
MyLoadString(IDS_MCIS_MAIL_ONLY_SETUP, csAppName);
}
else
{
MyLoadString(IDS_MAIL_ONLY, csProdName);
MyLoadString(IDS_MAIL_ONLY_SETUP, csAppName);
}
}
else
{
// NT5 - Use m_eNTOSType.
// TODO: Need to figure out the name for NT5 Server and NT5 Workstation NNTP service
if (theApp.m_eNTOSType == OT_NTS)
{
MyLoadString(IDS_MCIS_NEWS_ONLY, csProdName);
MyLoadString(IDS_MCIS_NEWS_ONLY_SETUP, csAppName);
}
else
{
MyLoadString(IDS_NEWS_ONLY, csProdName);
MyLoadString(IDS_NEWS_ONLY_SETUP, csAppName);
}
}
// Setup the name for the IIS Program group
MyLoadString(IDS_MAIL_AND_NEWS, theApp.m_csGroupName);
theApp.m_csProdName = csProdName;
theApp.m_csAppName = csAppName;
}
HRESULT MyCreateLink(LPCTSTR lpszPath, LPCTSTR lpszArgs, LPCTSTR lpszTarget, LPCTSTR lpszDir)
{
HRESULT hres;
IShellLink* pShellLink;
CoInitialize(NULL);
//CoInitialize must be called before this
// Get a pointer to the IShellLink interface.
hres = CoCreateInstance( CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink,
(LPVOID*)&pShellLink);
if (SUCCEEDED(hres))
{
IPersistFile* pPersistFile;
// Set the path to the shortcut target, and add the description.
pShellLink->SetPath(lpszPath);
pShellLink->SetArguments(lpszArgs);
pShellLink->SetWorkingDirectory(lpszDir);
// Query IShellLink for the IPersistFile interface for saving the
// shortcut in persistent storage.
hres = pShellLink->QueryInterface(IID_IPersistFile, (LPVOID*)&pPersistFile);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
#if defined(UNICODE) || defined(_UNICODE)
lstrcpy(wsz, lpszTarget);
#else
// Ensure that the string is WCHAR.
MultiByteToWideChar( CP_ACP,
0,
lpszTarget,
-1,
wsz,
MAX_PATH);
#endif
// Save the link by calling IPersistFile::Save.
hres = pPersistFile->Save(wsz, TRUE);
pPersistFile->Release();
}
pShellLink->Release();
}
CoUninitialize();
return hres;
}
BOOL MyDeleteLink(LPTSTR lpszShortcut)
{
TCHAR szFile[_MAX_PATH];
SHFILEOPSTRUCT fos;
ZeroMemory(szFile, sizeof(szFile));
lstrcpy(szFile, lpszShortcut);
// only call SHFileOperation if this file/link exists
if (0xFFFFFFFF != GetFileAttributes(szFile))
{
ZeroMemory(&fos, sizeof(fos));
fos.hwnd = NULL;
fos.wFunc = FO_DELETE;
fos.pFrom = szFile;
fos.fFlags = FOF_SILENT | FOF_NOCONFIRMATION;
SHFileOperation(&fos);
}
return TRUE;
}
void MyGetGroupPath(LPCTSTR szGroupName, LPTSTR szPath)
{
int nLen = 0;
LPITEMIDLIST pidlPrograms;
szPath[0] = NULL;
SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_PROGRAMS, &pidlPrograms);
SHGetPathFromIDList(pidlPrograms, szPath);
nLen = lstrlen(szPath);
if (szGroupName) {
if (nLen == 0 || szPath[nLen-1] != _T('\\'))
lstrcat(szPath, _T("\\"));
lstrcat(szPath, szGroupName);
}
return;
}
BOOL MyAddGroup(LPCTSTR szGroupName)
{
TCHAR szPath[MAX_PATH];
CString csPath;
MyGetGroupPath(szGroupName, szPath);
csPath = szPath;
CreateLayerDirectory(csPath);
SHChangeNotify(SHCNE_MKDIR, SHCNF_PATH, szPath, 0);
return TRUE;
}
BOOL MyIsGroupEmpty(LPCTSTR szGroupName)
{
TCHAR szPath[MAX_PATH];
TCHAR szFile[MAX_PATH];
WIN32_FIND_DATA FindData;
HANDLE hFind;
BOOL bFindFile = TRUE;
BOOL fReturn = TRUE;
MyGetGroupPath(szGroupName, szPath);
lstrcpy(szFile, szPath);
lstrcat(szFile, _T("\\*.*"));
hFind = FindFirstFile(szFile, &FindData);
if (INVALID_HANDLE_VALUE != hFind)
{
while (bFindFile)
{
if(*(FindData.cFileName) != _T('.'))
{
fReturn = FALSE;
break;
}
//find the next file
bFindFile = FindNextFile(hFind, &FindData);
}
FindClose(hFind);
}
return fReturn;
}
BOOL MyDeleteGroup(LPCTSTR szGroupName)
{
TCHAR szPath[MAX_PATH];
TCHAR szFile[MAX_PATH];
SHFILEOPSTRUCT fos;
WIN32_FIND_DATA FindData;
HANDLE hFind;
BOOL bFindFile = TRUE;
BOOL fResult;
MyGetGroupPath(szGroupName, szPath);
//we can't remove a directory that is not empty, so we need to empty this one
lstrcpy(szFile, szPath);
lstrcat(szFile, _T("\\*.*"));
ZeroMemory(&fos, sizeof(fos));
fos.hwnd = NULL;
fos.wFunc = FO_DELETE;
fos.fFlags = FOF_SILENT | FOF_NOCONFIRMATION;
hFind = FindFirstFile(szFile, &FindData);
if (INVALID_HANDLE_VALUE != hFind)
{
while (bFindFile)
{
if(*(FindData.cFileName) != _T('.'))
{
//copy the path and file name to our temp buffer
lstrcpy(szFile, szPath);
lstrcat(szFile, _T("\\"));
lstrcat(szFile, FindData.cFileName);
//add a second NULL because SHFileOperation is looking for this
lstrcat(szFile, _T("\0"));
//delete the file
fos.pFrom = szFile;
SHFileOperation(&fos);
}
//find the next file
bFindFile = FindNextFile(hFind, &FindData);
}
FindClose(hFind);
}
fResult = RemoveDirectory(szPath);
if (fResult)
{
SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, szPath, 0);
}
return(fResult);
}
void MyAddItem(LPCTSTR szGroupName, LPCTSTR szItemDesc, LPCTSTR szProgram, LPCTSTR szArgs, LPCTSTR szDir)
{
TCHAR szPath[_MAX_PATH];
MyGetGroupPath(szGroupName, szPath);
if (!IsFileExist(szPath))
MyAddGroup(szGroupName);
lstrcat(szPath, _T("\\"));
lstrcat(szPath, szItemDesc);
lstrcat(szPath, _T(".lnk"));
MyCreateLink(szProgram, szArgs, szPath, szDir);
}
void MyDeleteItem(LPCTSTR szGroupName, LPCTSTR szAppName)
{
TCHAR szPath[_MAX_PATH];
MyGetGroupPath(szGroupName, szPath);
lstrcat(szPath, _T("\\"));
lstrcat(szPath, szAppName);
lstrcat(szPath, _T(".lnk"));
MyDeleteLink(szPath);
if (MyIsGroupEmpty(szGroupName))
MyDeleteGroup(szGroupName);
}
// Use to delete files with extension other than ".lnk"
void MyDeleteItemEx(LPCTSTR szGroupName, LPCTSTR szAppName)
{
TCHAR szPath[_MAX_PATH];
MyGetGroupPath(szGroupName, szPath);
lstrcat(szPath, _T("\\"));
lstrcat(szPath, szAppName);
MyDeleteLink(szPath);
if (MyIsGroupEmpty(szGroupName))
MyDeleteGroup(szGroupName);
}
BOOL CreateISMLink()
{
// add items to the program group
CString csGroupName;
CString csNiceName;
CString csArgs;
CString csTemp;
CString csMmc;
DebugOutput(_T("Creating ISM link ..."));
// Get the program group name from the private data
GetIISProgramGroup(csGroupName, TRUE);
MyLoadString(IDS_PROGGROUP_MCIS_MAIL_AND_NEWS, csTemp);
MyLoadString(IDS_MMC, csMmc);
MyLoadString(IDS_ITEMPATH_ISM, csArgs);
// Build the program group
csGroupName += csTemp;
MyLoadString(IDS_PROGITEM_ISM, csNiceName);
MyAddItem(csGroupName, csNiceName, csMmc, csArgs, NULL);
return(TRUE);
}
BOOL RemoveISMLink()
{
// add items to the program group
CString csGroupName;
CString csNiceName;
CString csTemp;
DebugOutput(_T("Removing ISM link ..."));
// Get the program group name from the private data
GetIISProgramGroup(csGroupName, TRUE);
MyLoadString(IDS_PROGGROUP_MCIS_MAIL_AND_NEWS, csTemp);
// Build the program group
csGroupName += csTemp;
MyLoadString(IDS_PROGITEM_ISM, csNiceName);
MyDeleteItem(csGroupName, csNiceName);
return(TRUE);
}
class CDwordQueue
{
private:
DWORD dwInstances;
DWORD dwDequeuePtr;
DWORD dwMaxInstances;
DWORD_PTR *rgdwInstanceIds;
public:
CDwordQueue()
{
dwInstances = 0;
dwMaxInstances = 0;
dwDequeuePtr = 0;
rgdwInstanceIds = NULL;
}
~CDwordQueue()
{
if (rgdwInstanceIds)
{
LocalFree(rgdwInstanceIds);
rgdwInstanceIds = NULL;
}
}
BOOL QueueDword(DWORD_PTR dwValue);
BOOL DequeueDword(PDWORD_PTR pdwValue);
};
BOOL CDwordQueue::QueueDword(DWORD_PTR dwValue)
{
if (dwInstances == dwMaxInstances)
{
if (!dwMaxInstances)
dwMaxInstances = 1024;
else
dwMaxInstances <<= 1;
if (rgdwInstanceIds)
{
DWORD_PTR *pdwNew;
pdwNew = (PDWORD_PTR)LocalReAlloc(rgdwInstanceIds,
dwMaxInstances * sizeof(DWORD_PTR),
0);
if (!pdwNew)
return(FALSE);
rgdwInstanceIds = pdwNew;
}
else
{
rgdwInstanceIds = (PDWORD_PTR)LocalAlloc(0,
dwMaxInstances * sizeof(DWORD_PTR));
if (!rgdwInstanceIds)
return(FALSE);
}
}
rgdwInstanceIds[dwInstances++] = dwValue;
return(TRUE);
}
BOOL CDwordQueue::DequeueDword(PDWORD_PTR pdwValue)
{
if (dwDequeuePtr >= dwInstances)
return(FALSE);
*pdwValue = rgdwInstanceIds[dwDequeuePtr++];
return(TRUE);
}
BOOL UpdateServiceParameters(LPCTSTR szServiceName)
{
CString csKeyName;
CMDKey mKey;
CString csInstance;
CString csParameters;
CDwordQueue dwqQueue;
csKeyName = _T("LM/");
csKeyName += szServiceName;
mKey.OpenNode((LPCTSTR)csKeyName);
if ( (METADATA_HANDLE)mKey )
{
CMDKeyIter enumKey(mKey);
enumKey.Reset();
// Process all instances
while (enumKey.Next(&csInstance) == NO_ERROR)
{
if (dwqQueue.QueueDword(_ttol((LPCTSTR)csInstance)))
DebugOutput(_T("Read instance #%s"), (LPCTSTR)csInstance);
else
DebugOutput(_T("Error allocating buffer, skipping remaining instances"));
}
}
mKey.Close();
CMDKey mInstKey;
CMDKey mParamKey;
METADATA_RECORD mdRec;
DWORD_PTR i;
DWORD dwIndex = 0;
BYTE pBuffer[2048];
while (dwqQueue.DequeueDword(&i))
{
// Build "LM/*Svc/#"
csInstance.Format(_T("%s/%u"),
(LPCTSTR)csKeyName,
(DWORD)i);
csParameters = csInstance + _T("/Parameters");
DebugOutput(_T("Processing %s ..."), (LPCTSTR)csParameters);
dwIndex = 0;
while (1)
{
mParamKey.OpenNode(csParameters);
if ( (METADATA_HANDLE)mParamKey )
{
mdRec.dwMDIdentifier = 0;
mdRec.dwMDAttributes = METADATA_NO_ATTRIBUTES;
mdRec.dwMDUserType = 0;
mdRec.dwMDDataType = 0;
mdRec.dwMDDataLen = sizeof(pBuffer);
mdRec.pbMDData = pBuffer;
// Get the next value
if (!mParamKey.EnumData(dwIndex++, &mdRec))
{
mParamKey.Close();
break;
}
mParamKey.Close();
DebugOutput(_T("Read %s/%u"),
(LPCTSTR)csParameters,
mdRec.dwMDIdentifier);
// Migrate the value from the parameters level
// to instance level
mInstKey.OpenNode(csInstance);
if ( (METADATA_HANDLE)mInstKey )
{
DebugOutput(_T("Writing %s/%u"),
(LPCTSTR)csInstance,
mdRec.dwMDIdentifier);
mInstKey.SetData(&mdRec);
mInstKey.Close();
}
else
{
DebugOutput(_T("ERROR: Failed to open %s for writing"), csInstance);
}
}
else
{
DebugOutput(_T("Failed to open %s for enumeration"), csParameters);
break;
}
}
}
// Delete the parameters key
mInstKey.OpenNode(csInstance);
if ( (METADATA_HANDLE)mInstKey )
{
mInstKey.DeleteNode(_T("Parameters"));
mInstKey.Close();
}
return(TRUE);
}
BOOL rRemapKey(CString &csBaseName, DWORD dwBase, DWORD dwRegionSize, DWORD dwNewBase)
{
CString csPathName;
CMDKey mKey;
METADATA_RECORD mdRec;
DWORD dwIndex = 0;
DWORD_PTR dwId;
BYTE pBuffer[2048];
DebugOutput(_T("Remapping values under %s..."), (LPCTSTR)csBaseName);
mKey.OpenNode((LPCTSTR)csBaseName);
if (!(METADATA_HANDLE)mKey)
{
DebugOutput(_T("ERROR: Unable to open %s"), (LPCTSTR)csBaseName);
return(FALSE);
}
// Use pre-order traversal to remap all the IDs
{
CDwordQueue dwqRemap;
while (1)
{
mdRec.dwMDIdentifier = 0;
mdRec.dwMDAttributes = METADATA_NO_ATTRIBUTES;
mdRec.dwMDUserType = 0;
mdRec.dwMDDataType = 0;
mdRec.dwMDDataLen = sizeof(pBuffer);
mdRec.pbMDData = pBuffer;
// Get the next value
if (!mKey.EnumData(dwIndex++, &mdRec))
break;
// See if this is a record that we will have to migrate
dwId = mdRec.dwMDIdentifier;
DebugOutput(_T("Remapping %u if necessary ..."), (DWORD)dwId);
if ((dwId >= dwBase) &&
((dwId - dwBase) < dwRegionSize))
{
DebugOutput(_T("Id %u scheduled for remapping"), (DWORD)dwId);
dwqRemap.QueueDword(dwId);
}
}
while (dwqRemap.DequeueDword(&dwId))
{
// Remap value
mdRec.dwMDIdentifier = (DWORD)dwId;
mdRec.dwMDAttributes = 0;
mdRec.dwMDUserType = 0;
mdRec.dwMDDataType = 0;
mdRec.dwMDDataLen = sizeof(pBuffer);
mdRec.pbMDData = pBuffer;
mKey.GetData(&mdRec);
mdRec.dwMDIdentifier = ((DWORD)dwId - dwBase) + dwNewBase;
DebugOutput(_T("Remapping from %u to %u"), (DWORD)dwId,
mdRec.dwMDIdentifier);
mKey.SetData(&mdRec);
// Delete the original data
mKey.DeleteData((DWORD)dwId, mdRec.dwMDDataType);
}
}
CMDKeyIter enumKey(mKey);
LPTSTR pName;
CDwordQueue dwqQueue;
enumKey.Reset();
while(enumKey.Next(&csPathName) == NO_ERROR)
{
pName = (LPTSTR)LocalAlloc(0, (csPathName.GetLength() + 1) * sizeof(TCHAR));
if (pName)
{
lstrcpy(pName, (LPCTSTR)csPathName);
dwqQueue.QueueDword((DWORD_PTR)pName);
}
}
mKey.Close();
while (dwqQueue.DequeueDword((PDWORD_PTR)&pName))
{
csPathName = _T("/");
csPathName += pName;
csPathName = csBaseName + csPathName;
// Traverse all subnodes of this tree
rRemapKey(csPathName, dwBase, dwRegionSize, dwNewBase);
LocalFree(pName);
}
return(TRUE);
}
BOOL RemapServiceParameters(LPCTSTR szServiceName, DWORD dwBase, DWORD dwRegionSize, DWORD dwNewBase)
{
CString csKeyName;
CMDKey mKey;
csKeyName = _T("LM/");
csKeyName += szServiceName;
// Recursively walk the tree
rRemapKey(csKeyName, dwBase, dwRegionSize, dwNewBase);
return(TRUE);
}
void GetInetpubPathFromMD(CString& csPathInetpub)
{
TCHAR szw3root[] = _T("\\wwwroot");
TCHAR szPathInetpub[_MAX_PATH];
ZeroMemory( szPathInetpub, sizeof(szPathInetpub) );
CMDKey W3Key;
DWORD dwScratch;
DWORD dwType;
DWORD dwLength;
// Get W3Root path
W3Key.OpenNode(_T("LM/W3Svc/1/Root"));
if ( (METADATA_HANDLE)W3Key )
{
dwLength = _MAX_PATH;
if (W3Key.GetData(3001, &dwScratch, &dwScratch,
&dwType, &dwLength, (LPBYTE)szPathInetpub))
{
if (dwType == STRING_METADATA)
{
dwScratch = lstrlen(szw3root);
dwLength = lstrlen(szPathInetpub);
// If it ends with "\\wwwroot", then we copy the prefix into csPathInetpub
if ((dwLength > dwScratch) &&
!lstrcmpi(szPathInetpub + (dwLength - dwScratch), szw3root))
{
csPathInetpub.Empty();
lstrcpyn( csPathInetpub.GetBuffer(512), szPathInetpub, (dwLength - dwScratch + 1));
csPathInetpub.ReleaseBuffer();
}
// otherwise fall back to use the default...
}
}
W3Key.Close();
}
return;
}
BOOL GetActionFromCheckboxStateOnly(LPCTSTR SubcomponentId, ACTION_TYPE *pAction)
{
DWORD State = 0;
DWORD OldState = 0;
*pAction = AT_DO_NOTHING;
// Get the check box state
State = gHelperRoutines.QuerySelectionState(
gHelperRoutines.OcManagerContext,
SubcomponentId,
OCSELSTATETYPE_CURRENT
);
if (GetLastError() != NO_ERROR)
{
DebugOutput(_T("Failed to get current state for <%s> (%u)"),
SubcomponentId, GetLastError());
State = 0;
}
// Check orignal state
OldState = gHelperRoutines.QuerySelectionState(
gHelperRoutines.OcManagerContext,
SubcomponentId,
OCSELSTATETYPE_ORIGINAL
);
if (GetLastError() != NO_ERROR)
{
DebugOutput(_T("Failed to get original state for <%s> (%u)"),
SubcomponentId, GetLastError());
OldState = 0;
}
if (State && !OldState)
{
// Change in state from OFF->ON = install docs
*pAction = AT_FRESH_INSTALL;
DebugOutput(_T("Installing subcomponent <%s>"), SubcomponentId);
}
else if (!State && OldState)
{
// Change in state from ON->OFF = uninstall docs
*pAction = AT_REMOVE;
DebugOutput(_T("Removing subcomponent <%s>"), SubcomponentId);
}
else if (State && OldState &&
(GetIMSSetupMode() == IIS_SETUPMODE_REINSTALL))
{
// Reinstall if that's the current mode
*pAction = AT_REINSTALL;
DebugOutput(_T("Reinstalling subcomponent <%s>"), SubcomponentId);
}
return(TRUE);
}
enum DOMAIN_ROUTE_ACTION_TYPE
{
SMTP_NO_ACTION,
SMTP_DROP,
SMTP_SMARTHOST,
SMTP_SSL,
SMTP_ALIAS,
SMTP_DELIVER,
SMTP_DEFAULT,
LAST_SMTP_ACTION
};
const DWORD rgdwMapping[LAST_SMTP_ACTION] =
{
0x0, 0x1, 0x2, 0x4, 0x10, 0x20, 0x40
};
const DWORD dwEtrnFlag = 0x200;
#define SMTP_MD_ID(x) (0x9000 + (x))
#define _TAB _T('\t')
#define _NULL _T('\0')
#define _COMMA _T(',')
BOOL ReformatDomainRoutingEntries(LPCTSTR szServiceName)
{
CString csKeyName;
CString csDomainName;
CString csActionType;
CString csDomainRoute;
CMDKey mKey;
METADATA_RECORD mdRec;
TCHAR MultiSz[1024];
DWORD cbMultiSz = 1024;
LPTSTR Ptr;
csKeyName = _T("LM/");
csKeyName += szServiceName;
csKeyName += _T("/1");
// Open the node
mKey.OpenNode((LPCTSTR)csKeyName);
if (!(METADATA_HANDLE)mKey)
{
DebugOutput(_T("ERROR: Unable to open %s"), (LPCTSTR)csKeyName);
return(FALSE);
}
// Get the domain routing MULTISZ value
mdRec.dwMDIdentifier = SMTP_MD_ID(56);
mdRec.dwMDAttributes = 0;
mdRec.dwMDUserType = 0;
mdRec.dwMDDataType = 0;
mdRec.dwMDDataLen = cbMultiSz;
mdRec.pbMDData = (LPBYTE)MultiSz;
if (!mKey.GetData(&mdRec))
{
DebugOutput(_T("ERROR: Unable to GetData on %u. We will not migrate Domain Routes."),
mdRec.dwMDIdentifier);
return(FALSE);
}
// Close it so we can open a child later
mKey.Close();
DebugOutput(_T("Processing Domain routes ..."));
// This is the base name for all domain routes
csKeyName += _T("/Domain/");
Ptr = MultiSz;
while (Ptr && *Ptr)
{
do
{
TCHAR szDomainName[325];
TCHAR szActionType[MAX_PATH + 1];
TCHAR szValue[256];
int i, Action, NewAction;
BOOL UseEtrn;
szDomainName[0] = _NULL;
szValue[0] = _NULL;
szActionType[0] = _NULL;
// skip whitespace
while( (*Ptr != _NULL) && (isspace (*Ptr) || (*Ptr == _TAB)))
Ptr++;
if(*Ptr == _NULL)
break;
//get the Action
for (i = 0; *Ptr != 0 && *Ptr != _COMMA && i < 255; Ptr++)
{
szValue[i++] = *Ptr;
}
//null terminate
szValue[i] = _NULL;
Action = _wtoi(szValue);
if( (Action == 0) || (Action >= (int) LAST_SMTP_ACTION) || (*Ptr == _NULL))
{
DebugOutput(_T("%d is an invalid action"), Action);
//unknown action type
break;
}
DebugOutput(_T("Action = %u"), Action);
//skip ,
Ptr++;
// skip whitespace
while( (*Ptr != _NULL) && (isspace (*Ptr) || (*Ptr == _TAB)))
Ptr++;
//get the Domain
for (i = 0; *Ptr != 0 && *Ptr != _COMMA && i < 324; Ptr++)
{
szDomainName[i++] = *Ptr;
}
szDomainName[i] = _NULL;
csDomainName = szDomainName;
//check for bad data
if(szDomainName[0] == _NULL)
{
DebugOutput(_T("Found a NULL domain. Breaking out"));
break;
}
DebugOutput(_T("Domain = %s"), szDomainName);
//skip ,
Ptr++;
//get the Action
for (i = 0; Ptr != NULL && *Ptr != 0 && *Ptr != _COMMA && i < MAX_PATH; Ptr++)
{
szActionType[i++] = *Ptr;
}
szActionType[i] = _NULL;
csActionType = szActionType;
DebugOutput(_T("Action Type = %s"), szActionType);
//skip ,
Ptr++;
// skip whitespace
while( (*Ptr != _NULL) && (isspace (*Ptr) || (*Ptr == _TAB)))
Ptr++;
//get etrn
for (i = 0; *Ptr != 0 && *Ptr != _COMMA && i < 255; Ptr++)
{
szValue[i++] = *Ptr;
}
//null terminate
szValue[i] = _NULL;
UseEtrn = _wtoi(szValue);
//turn the number into a BOOL
UseEtrn = !!UseEtrn;
DebugOutput(_T("Use Etrn = %s"), UseEtrn?_T("TRUE"):_T("FALSE"));
// We don't deliver, so we coerce delivery to alias
if (Action == SMTP_DELIVER)
Action = SMTP_ALIAS;
// OK, we have come this far, so we can now write out the new
// domain routing entry
// First, remap the Action value, sinc eit had been changed.
NewAction = rgdwMapping[Action];
if (UseEtrn)
NewAction |= dwEtrnFlag;
// The Domain Name string that we get will become the new
// key name under smtpsvc/1/Domain/"Domain Name"
csDomainRoute = csKeyName + csDomainName;
DebugOutput(_T("Creating %s ..."), (LPCTSTR)csDomainName);
mKey.CreateNode(METADATA_MASTER_ROOT_HANDLE, (LPCTSTR)csDomainRoute);
if ( (METADATA_HANDLE)mKey )
{
// First set the route action DWORD
DebugOutput(_T("Creating route action = %08x"), NewAction);
mdRec.dwMDIdentifier = SMTP_MD_ID(82);
mdRec.dwMDAttributes = 1;
mdRec.dwMDUserType = 1;
mdRec.dwMDDataType = 1;
mdRec.dwMDDataLen = sizeof(DWORD);
mdRec.pbMDData = (LPBYTE)&NewAction;
mKey.SetData(&mdRec);
// Then set the route action type string
DebugOutput(_T("Creating route action type = %s"), (LPCTSTR)csActionType);
mdRec.dwMDIdentifier = SMTP_MD_ID(83);
mdRec.dwMDAttributes = 1;
mdRec.dwMDUserType = 1;
mdRec.dwMDDataType = 2;
mdRec.dwMDDataLen = (lstrlen(szActionType) + 1) * sizeof(TCHAR);
mdRec.pbMDData = (LPBYTE)szActionType;
mKey.SetData(&mdRec);
// Then set the KeyType
lstrcpy(szActionType, _T("IIsSmtpDomain"));
DebugOutput(_T("Creating Key type = %s"), szActionType);
mdRec.dwMDIdentifier = 1002;
mdRec.dwMDAttributes = 1;
mdRec.dwMDUserType = 1;
mdRec.dwMDDataType = 2;
mdRec.dwMDDataLen = (lstrlen(szActionType) + 1) * sizeof(TCHAR);
mdRec.pbMDData = (LPBYTE)szActionType;
mKey.SetData(&mdRec);
mKey.Close();
}
} while (0);
// We skip to the end of the current string and process the next one
// This makes sure we will not be in trouble when we break out in the
// middle of parsing
while (*Ptr++ != _NULL)
;
}
return(TRUE);
}
// IIS SnapIn CLSID - {A841B6C4-7577-11d0-BB1F-00A0C922E79C}
//DEFINE_GUID(CLSID_IIS_SnapIn, 0xa841b6c4, 0x7577, 0x11d0, 0xbb, 0x1f, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x9c);
const WCHAR * wszIIS_SnapIn = _T("{A841B6C4-7577-11d0-BB1F-00A0C922E79C}");
BOOL
EnableSnapInExtension(
IN CString &csMMCDocFilePath,
IN LPCWSTR lpwszExtSnapInCLSID,
IN BOOL bEnable
)
/*++
Description:
Enable/Disable snapin extension in IIS
NT5 - also enable our snapin under %systemroot%\system32\compmgmt.msc
Arguments:
csMMCDocFilePath - Path to iis.msc, normally %windir%\system32\inetsrv
ExtCLSID - CLSID for snapin extension
bEnable - TRUE enable, FALSE disable
Return Value:
TRUE - success, FALSE otherwise
--*/
{
// -------------------------------------------------------------------------------------
// $BUG(garypur) - removing the use of the IDocConfig interface since MMC support for it
// has been removed
// -------------------------------------------------------------------------------------
return TRUE;
/*
HRESULT hr = S_OK;
IDocConfig *pIDocConfig = NULL;
CString csMMCDocFile = csMMCDocFilePath;
VARIANT_BOOL boolVal = bEnable ? VARIANT_TRUE : VARIANT_FALSE;
BSTR bstrMMCDocFile;
BSTR bstrCLSID_IIS_SnapIn;
BSTR bstrCLSID_Ext_SnapIn;
hr = CoInitialize(NULL);
if (FAILED(hr))
{
DebugOutput(_T("Cannot CoInitialize()"));
return FALSE;
}
bstrMMCDocFile = ::SysAllocString((LPCWSTR) csMMCDocFile);
bstrCLSID_IIS_SnapIn = ::SysAllocString(wszIIS_SnapIn);
bstrCLSID_Ext_SnapIn = ::SysAllocString(lpwszExtSnapInCLSID);
//
// Get the IDocConfig interface pointer
//
hr = CoCreateInstance( (REFCLSID) CLSID_MMCDocConfig,
NULL,
CLSCTX_INPROC_SERVER,
(REFIID) IID_IDocConfig,
(void**) &pIDocConfig);
if (FAILED(hr))
goto exit;
//
// Open iis.msc
//
hr = pIDocConfig->OpenFile( bstrMMCDocFile );
if (FAILED(hr))
goto exit;
//
// Enable the Snapin
//
hr = pIDocConfig->EnableSnapInExtension( bstrCLSID_IIS_SnapIn, bstrCLSID_Ext_SnapIn, boolVal );
if (FAILED(hr))
goto exit;
//
// Save the change
//
hr = pIDocConfig->SaveFile( bstrMMCDocFile );
if (FAILED(hr))
goto exit;
//
// Close file
//
hr = pIDocConfig->CloseFile();
exit:
if (pIDocConfig)
{
pIDocConfig->Release();
pIDocConfig = NULL;
}
::SysFreeString(bstrMMCDocFile);
::SysFreeString(bstrCLSID_IIS_SnapIn);
::SysFreeString(bstrCLSID_Ext_SnapIn);
CoUninitialize();
return (S_OK == hr);
*/
}
const LPCTSTR g_cszMMCBasePath = _T("Software\\Microsoft\\MMC");
const LPCTSTR g_cszNodeTypes = _T("NodeTypes");
const LPCTSTR g_cszExtensions = _T("Extensions");
const LPCTSTR g_cszNameSpace = _T("NameSpace");
const LPCTSTR g_cszDynamicExt = _T("Dynamic Extensions");
const LPCTSTR g_cszServerAppsLoc = _T("System\\CurrentControlSet\\Control\\Server Applications");
BOOL
EnableCompMgmtExtension(
IN LPCWSTR lpwszExtSnapInCLSID,
IN LPCWSTR lpwszSnapInName,
IN BOOL bEnable
)
/*++
Description:
Enable/Disable snapin extension in NT5 CompMgmt
Arguments:
ExtCLSID - CLSID for snapin extension
bEnable - TRUE enable, FALSE disable
Return Value:
TRUE - success, FALSE otherwise
--*/
{
DebugOutput(_T("EnableCompMgmtExtension(): bEnable=%d"), bEnable);
CString strExtKey;
// set up registry values
CRegKey regMachine = HKEY_LOCAL_MACHINE;
if (bEnable)
{
{
//
// Register as a dynamic extension to computer management
//
strExtKey.Format(
_T("%s\\%s\\%s\\%s"),
g_cszMMCBasePath,
g_cszNodeTypes,
lstruuidNodetypeServerApps,
g_cszDynamicExt
);
CRegKey regMMCNodeTypes(strExtKey, regMachine);
if ((HKEY) regMMCNodeTypes)
{
regMMCNodeTypes.SetValue( lpwszExtSnapInCLSID, lpwszSnapInName );
}
}
{
//
// Register as a namespace extension to computer management
//
strExtKey.Format(
_T("%s\\%s\\%s\\%s\\%s"),
g_cszMMCBasePath,
g_cszNodeTypes,
lstruuidNodetypeServerApps,
g_cszExtensions,
g_cszNameSpace
);
CRegKey regMMCNodeTypes(strExtKey, regMachine);
if ((HKEY) regMMCNodeTypes)
{
regMMCNodeTypes.SetValue( lpwszExtSnapInCLSID, lpwszSnapInName );
}
}
//
// This key indicates that the service in question is available
// on the local machine
//
CRegKey regCompMgmt(g_cszServerAppsLoc, regMachine );
if ((HKEY) regCompMgmt)
{
regCompMgmt.SetValue( lpwszExtSnapInCLSID, lpwszSnapInName );
}
}
else
{
//
// Disabling CompMgmt extension
//
{
//
// Unregister as a dynamic extension to computer management
//
strExtKey.Format(
_T("%s\\%s\\%s\\%s"),
g_cszMMCBasePath,
g_cszNodeTypes,
lstruuidNodetypeServerApps,
g_cszDynamicExt
);
CRegKey regMMCNodeTypes(strExtKey, regMachine);
if ((HKEY) regMMCNodeTypes)
{
regMMCNodeTypes.DeleteValue( lpwszExtSnapInCLSID );
}
}
{
//
// unregister as a namespace extension to computer management
//
strExtKey.Format(
_T("%s\\%s\\%s\\%s\\%s"),
g_cszMMCBasePath,
g_cszNodeTypes,
lstruuidNodetypeServerApps,
g_cszExtensions,
g_cszNameSpace
);
CRegKey regMMCNodeTypes(strExtKey, regMachine);
if ((HKEY) regMMCNodeTypes)
{
regMMCNodeTypes.DeleteValue( lpwszExtSnapInCLSID );
}
}
//
// This key indicates that the service in question is available
// on the local machine. Remove it
//
CRegKey regCompMgmt(g_cszServerAppsLoc, regMachine );
if ((HKEY) regCompMgmt)
{
regCompMgmt.DeleteValue( lpwszExtSnapInCLSID );
}
}
return TRUE;
}