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.
1109 lines
36 KiB
1109 lines
36 KiB
// main.cpp : Implementation of DLL Exports.
|
|
|
|
#include "StdAfx.h"
|
|
#include "resource.h"
|
|
#include "main.h"
|
|
#include "PromptForPathDlg.h"
|
|
#include "cmdline.h"
|
|
#include <shlobj.h>
|
|
#include "stdio.h"
|
|
|
|
CComModule _Module;
|
|
|
|
VOID DisableBalloons( BOOL bDisable );
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
VOID AddBS( TCHAR* psz )
|
|
{
|
|
if( !_tcslen(psz) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
const TCHAR *szTemp = psz;
|
|
const UINT iSize = _tcslen(psz);
|
|
// MBCS-safe walk thru string to last char
|
|
for (UINT ui = 0; ui < iSize; ui++)
|
|
szTemp = CharNext(szTemp);
|
|
|
|
// See if the last char is a "\"
|
|
if (_tcsncmp( szTemp, _T("\\"), 1))
|
|
{
|
|
// Append a backslash
|
|
_tcscat( psz, _T("\\") );
|
|
}
|
|
|
|
}
|
|
|
|
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
|
|
{
|
|
USES_CONVERSION;
|
|
CoInitialize(NULL);
|
|
_Module.Init(NULL, hInstance);
|
|
TCHAR* pszLocation = NULL;
|
|
|
|
// Necessary to grab argv[0] too so we can successfully parse argv[1] flag later... (_FindOption)
|
|
lpCmdLine = GetCommandLine();
|
|
|
|
if ( _tcsstr(lpCmdLine, _T("winsb")) )
|
|
{
|
|
g_bWinSB = TRUE;
|
|
}
|
|
else
|
|
{
|
|
g_bWinSB = FALSE;
|
|
}
|
|
|
|
INT iRetVal = 0;
|
|
TCHAR szPath[MAX_PATH * 2];
|
|
|
|
g_bSBS = FALSE;
|
|
OSVERSIONINFO cInfo;
|
|
cInfo.dwOSVersionInfoSize = sizeof( cInfo );
|
|
if (!GetVersionEx( &cInfo ))
|
|
goto CLEAN_UP;
|
|
|
|
if( cInfo.dwMajorVersion >= 5 )
|
|
{
|
|
OSVERSIONINFOEX cInfoEx;
|
|
cInfoEx.dwOSVersionInfoSize = sizeof( cInfoEx );
|
|
GetVersionEx( (OSVERSIONINFO*)&cInfoEx );
|
|
if( (cInfoEx.wSuiteMask & VER_SUITE_SMALLBUSINESS) || (cInfoEx.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED) )
|
|
{
|
|
g_bSBS = TRUE;
|
|
}
|
|
}
|
|
|
|
// Supress the balloons!!
|
|
DisableBalloons(TRUE);
|
|
|
|
// look for the /suppresscys switch
|
|
if( SUCCEEDED(CheckSuppressCYS(lpCmdLine)) )
|
|
{
|
|
goto CLEAN_UP;
|
|
}
|
|
|
|
// look for the /dcpromo switch on the command line. if it's there, setup to re-startup
|
|
// with the rest of the command line, and then launch dcpromo.exe
|
|
if( SUCCEEDED(CheckDCPromoSwitch(lpCmdLine)) )
|
|
{
|
|
// can check here for needing to show a message (i.e. if hr == S_FALSE)
|
|
goto CLEAN_UP;
|
|
}
|
|
|
|
// if we didn't find /dcpromo, look for /bossetup and /bosunattend
|
|
if( SUCCEEDED(CheckBOSSwitch(lpCmdLine)) )
|
|
{
|
|
// can check here for needing to show a message (i.e. if hr == S_FALSE)
|
|
goto CLEAN_UP;
|
|
}
|
|
|
|
// Parse the cmdLine arguments to find out if we are setting up for BOS/SBS 5.0 Setup.
|
|
INT iRunSetup = ParseCmdLine( lpCmdLine );
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Parse command line the "real" way to look for the /l <setup location>
|
|
// parameter.
|
|
// ------------------------------------------------------------------------
|
|
pszLocation = new TCHAR[_tcslen(lpCmdLine)+1];
|
|
if ( !pszLocation )
|
|
{
|
|
goto CLEAN_UP;
|
|
}
|
|
|
|
_tcscpy( pszLocation, _T("") );
|
|
if( pszLocation != NULL )
|
|
{
|
|
LPCTSTR lpszToken;
|
|
LPTSTR pszCurrentPos;
|
|
|
|
for ( lpszToken = _FindOption(lpCmdLine) ; // Init to no bad usage and get the first param.
|
|
(lpszToken != NULL) && (pszCurrentPos = const_cast<LPTSTR>(lpszToken)) ; // While no bad usage and we still have a param...
|
|
lpszToken = _FindOption(pszCurrentPos) ) // Get the next parameter.
|
|
{
|
|
switch(*pszCurrentPos)
|
|
{
|
|
case _T('l'): // /l <setup location>
|
|
case _T('L'):
|
|
{
|
|
_ReadParam(pszCurrentPos, pszLocation);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ( iRunSetup )
|
|
{
|
|
// safely construct path from commandline if it exists.
|
|
AddBS(pszLocation);
|
|
|
|
INT iLaunchSetup = 1;
|
|
CComBSTR bszPath = pszLocation ? pszLocation : _T("");
|
|
CComBSTR bszFilename = _T("setup.exe");
|
|
|
|
CComBSTR bszSetupFile = _T("");
|
|
bszSetupFile += bszPath;
|
|
bszSetupFile += bszFilename;
|
|
|
|
// First try out the path we got from the command line
|
|
if( !VerifyPath((TCHAR*)OLE2T(bszSetupFile)) )
|
|
{
|
|
// If not, try getting one from the registry.
|
|
TCHAR * szSourcePath = new TCHAR[MAX_PATH];
|
|
if (szSourcePath)
|
|
{
|
|
if ( !GetSourcePath( szSourcePath, MAX_PATH ) )
|
|
{
|
|
// Error reading the registry.
|
|
szSourcePath[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
AddBS(szSourcePath);
|
|
}
|
|
|
|
bszPath = szSourcePath;
|
|
delete [] szSourcePath;
|
|
}
|
|
|
|
// Launch BO Setup
|
|
bszSetupFile = _T("");
|
|
bszSetupFile += bszPath;
|
|
bszSetupFile += bszFilename;
|
|
|
|
// Try the default directory.
|
|
if ( !VerifyPath((TCHAR*)OLE2T(bszSetupFile)) )
|
|
{
|
|
// If BOS/SBS setup.exe isn't there, prompt them for it.
|
|
iLaunchSetup = PromptForPath( &bszPath );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// clean off trailing backslash from bszPath so that the append of \setup.exe works.
|
|
// the conditional logic here is a little ugly, but it works.
|
|
|
|
WCHAR wszPath[MAX_PATH];
|
|
int cbPathSize;
|
|
|
|
wcscpy( wszPath, (WCHAR *)OLE2W(bszPath) );
|
|
cbPathSize = wcslen( wszPath );
|
|
wszPath[cbPathSize-1] = '\0';
|
|
bszPath = wszPath;
|
|
}
|
|
|
|
|
|
// If the user wants to run setup...
|
|
if ( iLaunchSetup )
|
|
{
|
|
CComBSTR bstrEXE = bszPath;
|
|
// NOTE: No longer branching here because both WinSB and SBS have the same CD layout now.
|
|
// if ( _tcsstr(lpCmdLine, _T("winsb")) ) // In the WinSB SKU, setup.exe is in a different dir.
|
|
// {
|
|
bstrEXE += _T("\\setup\\i386\\setup.exe");
|
|
// }
|
|
// else
|
|
// {
|
|
// bstrEXE += _T("\\sbs\\i386\\setup.exe");
|
|
// }
|
|
|
|
|
|
CComBSTR bstrRun = _T("setup.exe /chain");
|
|
|
|
// CreateProcess.
|
|
STARTUPINFO suinfo;
|
|
memset( &suinfo, 0, sizeof(STARTUPINFO) );
|
|
suinfo.cb = sizeof( STARTUPINFO );
|
|
PROCESS_INFORMATION pinfo;
|
|
|
|
if( CreateProcess( (TCHAR*)OLE2T(bstrEXE), (TCHAR*)OLE2T(bstrRun), NULL, NULL, FALSE, NULL, NULL, NULL, &suinfo, &pinfo) )
|
|
{
|
|
CloseHandle(pinfo.hProcess);
|
|
CloseHandle(pinfo.hThread);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Nothing I guess.. let's just continue on with the cleanup.
|
|
}
|
|
|
|
// Clean up (remove BOSPrep.exe).
|
|
TCHAR szSBS[MAX_PATH];
|
|
LoadString( _Module.m_hInst, IDS_SBSSwitch, szSBS, sizeof(szSBS) / sizeof(TCHAR) );
|
|
if( _tcsstr(lpCmdLine, szSBS) )
|
|
{
|
|
TCHAR szExe[MAX_PATH];
|
|
LoadString( _Module.m_hInst, IDS_EXEName, szExe, sizeof(szExe) / sizeof(TCHAR) );
|
|
|
|
SHGetSpecialFolderPath( NULL, szPath, CSIDL_SYSTEM, FALSE );
|
|
AddBS( szPath );
|
|
_tcscat( szPath, szExe );
|
|
}
|
|
else
|
|
{
|
|
TCHAR* szDrive = NULL;
|
|
GetSystemDrive(&szDrive);
|
|
lstrcpyn( szPath, szDrive, MAX_PATH );
|
|
delete [] szDrive;
|
|
|
|
AddBS( szPath );
|
|
_tcscat( szPath, _T("bosprep.exe"));
|
|
}
|
|
|
|
MoveFileEx( szPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT );
|
|
|
|
// Clean up (remove the shortcut from the StartUp folder).
|
|
TCHAR szLinkPath[MAX_PATH + 64];
|
|
if ( SHGetSpecialFolderPath(NULL, szLinkPath, CSIDL_COMMON_STARTUP, FALSE) )
|
|
{
|
|
TCHAR szTmp[64];
|
|
LoadString( _Module.m_hInst, IDS_BOlnk, szTmp, sizeof(szTmp)/sizeof(TCHAR) );
|
|
_tcscat( szLinkPath, szTmp );
|
|
DeleteFile( szLinkPath );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Fix up the userinit regkey to make sure that DCPromo.exe is not in there.
|
|
RemoveFromUserinit( _T("DCPromo") );
|
|
|
|
// Suppress the Configure Your Server page.
|
|
SuppressCfgSrvPage();
|
|
|
|
// Add ourself to the StartUp with the /setup option so that we can
|
|
// begin BackOffice setup.
|
|
TCHAR szLinkPath[MAX_PATH];
|
|
|
|
// JeffZi: bosprep.exe will be copied to %PROGFILESDIR%\Microsoft BackOffice\Setup, except for
|
|
// SBS clean install cases, where it will be in %windir%\system32
|
|
if( _tcsstr(lpCmdLine, _T("sbs")) || _tcsstr(lpCmdLine, _T("winsb")) )
|
|
{
|
|
TCHAR szExe[MAX_PATH];
|
|
LoadString( _Module.m_hInst, IDS_EXEName, szExe, sizeof(szExe) / sizeof(TCHAR) );
|
|
|
|
SHGetSpecialFolderPath( NULL, szPath, CSIDL_SYSTEM, FALSE );
|
|
AddBS( szPath );
|
|
_tcscat( szPath, szExe );
|
|
}
|
|
else
|
|
{
|
|
TCHAR* szDrive = NULL;
|
|
GetSystemDrive(&szDrive);
|
|
_tcsncpy( szPath, szDrive, sizeof(szPath) / sizeof(TCHAR) );
|
|
delete [] szDrive;
|
|
AddBS( szPath );
|
|
_tcscat( szPath, _T("bosprep.exe"));
|
|
}
|
|
|
|
if ( SHGetSpecialFolderPath(NULL, szLinkPath, CSIDL_COMMON_STARTUP, FALSE) )
|
|
{
|
|
TCHAR szArgs[128]; // Used for IDS_IDS_SetupSwitch ("/setup")
|
|
TCHAR szTmp[64]; // Used for IDS_BOlnk ("\\boinst.lnk")
|
|
|
|
LoadString( _Module.m_hInst, IDS_BOlnk, szTmp, sizeof(szTmp)/sizeof(TCHAR) );
|
|
_tcscat( szLinkPath, szTmp);
|
|
LoadString( _Module.m_hInst, IDS_SetupSwitch, szArgs, sizeof(szArgs)/sizeof(TCHAR) );
|
|
|
|
if ( _tcsstr(lpCmdLine, _T("winsb")) )
|
|
{
|
|
_tcscat( szArgs, _T(" /winsb") );
|
|
}
|
|
|
|
// Create the shortcut.
|
|
MakeLink(szPath, szLinkPath, szArgs);
|
|
}
|
|
|
|
// Set the AppCompatibility\store.exe regkeys for SBS only.
|
|
if ( g_bSBS )
|
|
{
|
|
HKEY hk = NULL;
|
|
CRegKey cKey;
|
|
DWORD dwSize = 0;
|
|
DWORD dwDisp = 0;
|
|
BYTE byTmp;
|
|
BYTE byArray[1024];
|
|
TCHAR szKeyName[1024];
|
|
TCHAR szTmpKey[1024];
|
|
TCHAR szTmpVal[4096];
|
|
TCHAR *pszToken = NULL;
|
|
|
|
memset(byArray, 0, 1024);
|
|
_tcscpy(szKeyName, _T(""));
|
|
_tcscpy(szTmpKey, _T(""));
|
|
_tcscpy(szTmpVal, _T(""));
|
|
|
|
LoadString( _Module.m_hInst, IDS_StoreExeKey, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
|
|
|
|
if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hk, &dwDisp) == ERROR_SUCCESS )
|
|
{
|
|
// "DllPatch-SBSUpgrade" = "_sbsw2ku.dll"
|
|
/* LoadString( _Module.m_hInst, IDS_DllPatchSBSUpgrade, szTmpKey, sizeof(szTmpKey)/sizeof(TCHAR) );
|
|
LoadString( _Module.m_hInst, IDS_DllPatchVal, szTmpVal, sizeof(szTmpVal)/sizeof(TCHAR) );
|
|
RegSetValueEx( hk, szTmpKey, NULL, REG_SZ, (LPBYTE)szTmpVal, (_tcslen(szTmpVal)+1)*sizeof(TCHAR) );
|
|
*/
|
|
// "SBSUpgrade"=hex:0C,00,00,00, ... etc
|
|
LoadString( _Module.m_hInst, IDS_SBSUpgrade, szTmpKey, sizeof(szTmpKey)/sizeof(TCHAR) );
|
|
LoadString( _Module.m_hInst, IDS_SBSUpgradeVal, szTmpVal, sizeof(szTmpVal)/sizeof(TCHAR) );
|
|
|
|
dwSize = 0;
|
|
pszToken = _tcstok(szTmpVal, ",");
|
|
while ( pszToken )
|
|
{
|
|
byTmp = 0;
|
|
if(1==_stscanf( pszToken, _T("%x"), &byTmp ))
|
|
{
|
|
byArray[dwSize++] = byTmp;
|
|
}
|
|
else
|
|
{
|
|
byArray[dwSize++]= 0;
|
|
}
|
|
pszToken = _tcstok(NULL, ",");
|
|
|
|
}
|
|
RegSetValueEx( hk, szTmpKey, NULL, REG_BINARY, byArray, dwSize );
|
|
|
|
cKey.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
CLEAN_UP:
|
|
// Exit.
|
|
if (pszLocation)
|
|
delete [] pszLocation;
|
|
CoUninitialize();
|
|
_Module.Term();
|
|
return iRetVal;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// parseCmdLine()
|
|
//
|
|
// Goes through the command line and checks if the "/setup" option is
|
|
// present. Since this program isn't really meant to be interactively
|
|
// launched by the user, we will be a little sloppy with the way we look
|
|
// at the commandline arguments. That is, instead of making sure that there
|
|
// is only one commandline argument, and that it "/setup"... we will instead
|
|
// just try to find "/setup" somewhere in the commandline.
|
|
//
|
|
// Return:
|
|
// 0 if the setup switch string was NOT found in the cmd line.
|
|
// 1 if the setup switch string WAS found in the cmd line.
|
|
// ----------------------------------------------------------------------------
|
|
INT ParseCmdLine( LPTSTR lpCmdLine )
|
|
{
|
|
TCHAR szSetup[MAX_PATH];
|
|
|
|
LoadString( _Module.m_hInst, IDS_SetupSwitch, szSetup, sizeof(szSetup)/sizeof(TCHAR) );
|
|
|
|
// If we find the setup switch string (/setup) in the cmd line, then we are setting
|
|
// up to run BackOffice setup, so we'll return 1.
|
|
if ( _tcsstr( lpCmdLine, szSetup ) )
|
|
return(1);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// promptForPath()
|
|
//
|
|
// Displays UI to the user asking for the location of the BackOffice 5 CD1
|
|
// so that we can launch setup.
|
|
//
|
|
// Return:
|
|
// 0 if the user pressed cancel when prompted for the path.
|
|
// 1 if we're ready to launch setup!
|
|
// ----------------------------------------------------------------------------
|
|
INT PromptForPath( BSTR* pbszPath )
|
|
{
|
|
USES_CONVERSION;
|
|
INT_PTR iRet = 0;
|
|
CPromptForPathDlg* pPromptDlg = NULL;
|
|
TCHAR szTmpMsg[MAX_PATH];
|
|
|
|
if( !pbszPath )
|
|
return (0);
|
|
|
|
CComBSTR bszDefault = *pbszPath;
|
|
if (!bszDefault)
|
|
return 0;
|
|
SysFreeString( *pbszPath );
|
|
HWND hWndParent = GetActiveWindow();
|
|
|
|
pPromptDlg = new CPromptForPathDlg( bszDefault, _Module.m_hInst, g_bWinSB );
|
|
if ( !pPromptDlg ) return(0);
|
|
|
|
bool bNotDone = true;
|
|
while (bNotDone == true)
|
|
{
|
|
iRet = pPromptDlg->DoModal( hWndParent );
|
|
pPromptDlg->m_hWnd = NULL;
|
|
if( iRet == IDOK )
|
|
{
|
|
// leave this as a SysAllocString
|
|
*pbszPath = SysAllocString( pPromptDlg->m_bszDef );
|
|
if (*pbszPath == NULL)
|
|
goto CLEAN_UP;
|
|
|
|
CComBSTR bszTmp = *pbszPath;
|
|
bszTmp += _T("\\setup.exe");
|
|
// Check if the path they chose was correct.
|
|
if ( VerifyPath((TCHAR*)OLE2T(bszTmp)) )
|
|
{
|
|
bNotDone = false; // If so, let's just move on.
|
|
}
|
|
else
|
|
{
|
|
bNotDone = true; // If not, ask again.
|
|
SysFreeString( *pbszPath );
|
|
LoadString( _Module.m_hInst, IDS_CantFindMsg, szTmpMsg, sizeof(szTmpMsg)/sizeof(TCHAR) );
|
|
TCHAR szTmpTitle[128];
|
|
LoadString( _Module.m_hInst, g_bWinSB ? IDS_WinSBTitle : IDS_SBSTitle, szTmpTitle, sizeof(szTmpTitle)/sizeof(TCHAR) );
|
|
::MessageBox( hWndParent, szTmpMsg, szTmpTitle, MB_OK | MB_ICONEXCLAMATION );
|
|
}
|
|
}
|
|
else if ( iRet == IDCANCEL )
|
|
{
|
|
INT iDoCancel = 0; // note we do NOT use iRet here
|
|
|
|
LoadString( _Module.m_hInst, g_bWinSB ? IDS_WinSBCancelCDPrompt : IDS_SBSCancelCDPrompt, szTmpMsg, sizeof(szTmpMsg)/sizeof(TCHAR) );
|
|
TCHAR szTmpTitle[MAX_PATH];
|
|
LoadString( _Module.m_hInst, g_bWinSB ? IDS_WinSBTitle : IDS_SBSTitle, szTmpTitle, sizeof(szTmpTitle)/sizeof(TCHAR) );
|
|
iDoCancel = ::MessageBox( hWndParent, szTmpMsg, szTmpTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2 );
|
|
|
|
if ( iDoCancel == IDYES )
|
|
{
|
|
bNotDone = false;
|
|
}
|
|
// else we will reprompt them for the CD
|
|
}
|
|
else
|
|
{
|
|
// we don't know how to handle any other return values
|
|
//::MessageBox(::GetForegroundWindow(), _T("AHhhhhhhhhhh"), _T("DEBUG"), MB_OK);
|
|
}
|
|
}
|
|
|
|
|
|
CLEAN_UP:
|
|
if (pPromptDlg)
|
|
{
|
|
delete pPromptDlg;
|
|
pPromptDlg = NULL;
|
|
}
|
|
|
|
return( iRet==IDOK ? 1 : 0 );
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// removeFromUserinit()
|
|
//
|
|
// Opens the Userinit registry key and searches for the 'szToRemove' string.
|
|
// If it finds the string, it removes that entry from the string.
|
|
// (i.e. it removes the string and also the following comma and spaces).
|
|
//
|
|
// NOTE: This function only removes the first occurance of the szToRemove.
|
|
// If you want to remove all occurances, simply loop around this
|
|
// function until the returned value is 0.
|
|
//
|
|
// Return:
|
|
// 0 if an error of any kind occured.
|
|
// 1 if everything went as planned.
|
|
// ----------------------------------------------------------------------------
|
|
INT RemoveFromUserinit(const TCHAR * szToRemove)
|
|
{
|
|
TCHAR szToRemCpy[MAX_PATH];
|
|
TCHAR szKeyName[MAX_PATH];
|
|
TCHAR * szBuffer = NULL;
|
|
TCHAR * szTmpBuf = NULL;
|
|
TCHAR * ptc = NULL;
|
|
TCHAR * p = NULL;
|
|
TCHAR * q = NULL;
|
|
DWORD dwOffset = 0;
|
|
DWORD dwLen = 0;
|
|
BOOL bAlreadyFixed = FALSE;
|
|
CRegKey cKey;
|
|
|
|
// Check to make sure a valid string was passed in.
|
|
// ASSERT(szToRemove);
|
|
if (!szToRemove)
|
|
return(0); // If error, return 0.
|
|
|
|
// Copy the passed in string to our "szToRemCpy"
|
|
_tcsncpy(szToRemCpy, szToRemove, MAX_PATH);
|
|
szToRemCpy[MAX_PATH-1] = 0;
|
|
|
|
// Try to open the regkey.
|
|
LoadString( _Module.m_hInst, IDS_UserInitKeyLoc, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
|
|
if ( cKey.Open(HKEY_LOCAL_MACHINE, szKeyName) != ERROR_SUCCESS )
|
|
return(0); // If error, return 0.
|
|
|
|
if ( !(szBuffer = new TCHAR[MAX_PATH]) ) // Malloc and check...
|
|
{
|
|
// ASSERT(FALSE);
|
|
cKey.Close(); // Close the regkey.
|
|
return(0); // If error, return 0.
|
|
}
|
|
|
|
// Try to get the value of "userinit"
|
|
dwLen = MAX_PATH;
|
|
LoadString( _Module.m_hInst, IDS_UserInitKeyName, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
|
|
if ( cKey.QueryValue(szBuffer, szKeyName, &dwLen) != ERROR_SUCCESS )
|
|
{
|
|
delete[] szBuffer; // Free up that memory.
|
|
cKey.Close(); // Close the regkey.
|
|
return(0); // If error, return 0.
|
|
}
|
|
|
|
_tcslwr(szBuffer); // Convert to lowercase.
|
|
_tcslwr(szToRemCpy); // Convert to lowercase.
|
|
|
|
// See if the 'szToRemCpy' string is in the userinit string.
|
|
if ( (ptc = _tcsstr(szBuffer, szToRemCpy)) == NULL )
|
|
{
|
|
delete[] szBuffer;
|
|
cKey.Close(); // Close the regkey.
|
|
return(0);
|
|
}
|
|
|
|
dwOffset = _tcslen(szToRemCpy);
|
|
for ( ; (ptc != szBuffer) && (*ptc != _T(',')); ptc--, dwOffset++ ); // Find the comma before this if it exists.
|
|
// AHHHHHHHHHHHHHHHHH.. fix that char (',').
|
|
if ( ptc != szBuffer ) // If we found a comma,
|
|
bAlreadyFixed = true; // then signal that we already removed a comma.
|
|
|
|
// Now that we know that the string to remove is indeed in the userinit regkey (and 'ptc' points to
|
|
// the beginning of that sub string), we can copy all of the old buffer into the new buffer and
|
|
// just omit the szToRemove part.
|
|
if ( !(szTmpBuf = new TCHAR[dwLen]) )
|
|
{
|
|
// ASSERT(FALSE);
|
|
delete[] szBuffer;
|
|
cKey.Close();
|
|
return(0);
|
|
}
|
|
|
|
// p = Source string
|
|
// q = Target string
|
|
for ( p = szBuffer, q = szTmpBuf; (*p != 0) && (p != ptc); *q++ = *p++ ); // Copy until we hit the beginning of what we want to remove.
|
|
if ( *p != 0 )
|
|
p += dwOffset; // Move our source pointer forward.
|
|
for ( ; (*p != 0) && (*p != _T(',')); p++ ); // AHHHHHHHHHHHHHHHHH.. fix that char (',').
|
|
if ( !bAlreadyFixed )
|
|
{ // If we haven't already removed a comma,
|
|
if (*p != 0)
|
|
p++; // then let's remove this one.
|
|
}
|
|
for ( ; (*p != 0) && (_istspace(*p)); p++ ); // Find the beginning of the next program.
|
|
for ( ; *p != 0; *q++ = *p++ ); // Now copy until the end.
|
|
*q = 0;
|
|
|
|
// Now right the new and improved string to the registry.
|
|
LoadString( _Module.m_hInst, IDS_UserInitKeyName, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
|
|
cKey.SetValue( szTmpBuf, szKeyName );
|
|
|
|
delete[] szTmpBuf; // Free up that memory.
|
|
delete[] szBuffer; // Free up that memory.
|
|
cKey.Close(); // Close the regkey.
|
|
|
|
return(1); // Return success.
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// suppressCfgSrvPage()
|
|
//
|
|
// Opens the "show" registry key and changes it's value to 0 to turn off the
|
|
// "Configure Your Server" screen.
|
|
//
|
|
// Return:
|
|
// 0 if an error of any kind occured.
|
|
// 1 if everything went as planned.
|
|
// ----------------------------------------------------------------------------
|
|
INT SuppressCfgSrvPage(void)
|
|
{
|
|
TCHAR szKeyName[MAX_PATH];
|
|
DWORD dwTmp=0;
|
|
CRegKey cKey;
|
|
|
|
// Try to open the regkey.
|
|
LoadString( _Module.m_hInst, IDS_CfgSrvKeyLoc, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
|
|
if ( cKey.Open(HKEY_CURRENT_USER, szKeyName) != ERROR_SUCCESS )
|
|
return(0); // If error, return 0.
|
|
|
|
// Try to set the value.
|
|
LoadString( _Module.m_hInst, IDS_CfgSrvKeyName, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
|
|
if ( cKey.SetValue(dwTmp, szKeyName) != ERROR_SUCCESS )
|
|
{
|
|
cKey.Close(); // Close the regkey.
|
|
return(0); // If error, return 0.
|
|
}
|
|
|
|
cKey.Close();
|
|
return(1);
|
|
}
|
|
|
|
|
|
INT GetSourcePath( TCHAR * szPath, DWORD dwCount )
|
|
{
|
|
TCHAR szKeyName[MAX_PATH];
|
|
CRegKey cKey;
|
|
DWORD dw = dwCount;
|
|
|
|
// Try to open the regkey.
|
|
LoadString( _Module.m_hInst, IDS_SourcePathLoc, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
|
|
if ( cKey.Open(HKEY_LOCAL_MACHINE, szKeyName) != ERROR_SUCCESS )
|
|
return(0);
|
|
|
|
// Try to get the value
|
|
LoadString( _Module.m_hInst, IDS_SourcePathName, szKeyName, sizeof(szKeyName)/sizeof(TCHAR) );
|
|
if ( cKey.QueryValue( szPath, szKeyName, &dw ) != ERROR_SUCCESS )
|
|
{
|
|
cKey.Close();
|
|
return(0);
|
|
}
|
|
|
|
cKey.Close();
|
|
return(1);
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// verifyPath()
|
|
//
|
|
// Checks to make sure that the BOS/SBS setup.exe exists at the given location.
|
|
//
|
|
// Returns:
|
|
// 0 if BOS/SBS setup was not found at that location
|
|
// 1 if setup WAS found at the location.
|
|
// ----------------------------------------------------------------------------
|
|
INT VerifyPath( const TCHAR *szPath )
|
|
{
|
|
if( !szPath )
|
|
return (0);
|
|
|
|
return (INVALID_FILE_ATTRIBUTES != GetFileAttributes(szPath));
|
|
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// makeLink()
|
|
//
|
|
// This function creates a shortcut, "sourcePath," that points to "linkPath"
|
|
// with the commandline arguments of "args."
|
|
//
|
|
// Return:
|
|
// S_OK if the shortcut was successfully created.
|
|
// Some sort of error (FAILED(hr)) if any error occured.
|
|
// ----------------------------------------------------------------------------
|
|
HRESULT MakeLink(const TCHAR* const sourcePath, const TCHAR* const linkPath, const TCHAR* const args)
|
|
{
|
|
if ( !sourcePath || !linkPath || !args )
|
|
return(E_FAIL);
|
|
|
|
IShellLink* pShellLink = NULL;
|
|
HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IShellLink, reinterpret_cast<void**>(&pShellLink));
|
|
if (FAILED(hr))
|
|
goto CLEAN_UP;
|
|
|
|
hr = pShellLink->SetPath(sourcePath);
|
|
if (FAILED(hr))
|
|
goto CLEAN_UP;
|
|
|
|
hr = pShellLink->SetArguments(args);
|
|
if (FAILED(hr))
|
|
goto CLEAN_UP;
|
|
|
|
IPersistFile* pPersistFile = NULL;
|
|
hr = pShellLink->QueryInterface(IID_IPersistFile, reinterpret_cast<void**>(&pPersistFile));
|
|
if (FAILED(hr))
|
|
goto CLEAN_UP;
|
|
|
|
USES_CONVERSION;
|
|
hr = pPersistFile->Save(T2OLE(linkPath), TRUE);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
CLEAN_UP:
|
|
if (pPersistFile)
|
|
pPersistFile->Release();
|
|
if (pShellLink)
|
|
pShellLink->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CheckDCPromoSwitch( TCHAR* pszCmdLine )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComBSTR bstrRun;
|
|
CComBSTR bstrEXE;
|
|
|
|
TCHAR* pszDCPromo = NULL;
|
|
TCHAR* pszBOSUnattend = NULL;
|
|
TCHAR* pszBOSSetup = NULL;
|
|
TCHAR* pszNewCmd = NULL;
|
|
|
|
if (!pszCmdLine)
|
|
return E_INVALIDARG;
|
|
|
|
pszDCPromo = new TCHAR[_tcslen(pszCmdLine) + 1];
|
|
if (!pszDCPromo)
|
|
return E_OUTOFMEMORY;
|
|
|
|
GetParameter( pszCmdLine, _T("/dcpromo"), pszDCPromo );
|
|
if( !_tcslen(pszDCPromo) )
|
|
{
|
|
hr = E_FAIL;
|
|
goto CLEAN_UP;
|
|
}
|
|
|
|
// make sure that /bosunattend and /bossetup are on the cmd line as well
|
|
pszBOSUnattend = new TCHAR[_tcslen(pszCmdLine) + 1];
|
|
if (!pszBOSUnattend)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto CLEAN_UP;
|
|
}
|
|
GetParameter( pszCmdLine, _T("/bosunattend"), pszBOSUnattend );
|
|
|
|
pszBOSSetup = new TCHAR[_tcslen(pszCmdLine) + 1];
|
|
if (!pszBOSSetup)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto CLEAN_UP;
|
|
}
|
|
GetParameter( pszCmdLine, _T("/bossetup"), pszBOSSetup );
|
|
|
|
if( !_tcslen(pszBOSSetup) || !_tcslen(pszBOSUnattend) )
|
|
{
|
|
hr = S_FALSE;
|
|
goto CLEAN_UP;
|
|
}
|
|
|
|
// build the new command line (basically remove the dcpromo switch)
|
|
pszNewCmd = new TCHAR[_tcslen(pszBOSSetup) + _tcslen(pszBOSUnattend) + MAX_PATH];
|
|
if (!pszNewCmd)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto CLEAN_UP;
|
|
}
|
|
|
|
_tcscpy( pszNewCmd, _T("/bosunattend ") );
|
|
_tcscat( pszNewCmd, pszBOSUnattend );
|
|
_tcscat( pszNewCmd, _T(" /bossetup ") );
|
|
_tcscat( pszNewCmd, pszBOSSetup );
|
|
|
|
// get the path to our exe
|
|
TCHAR szOurPath[MAX_PATH * 2];
|
|
if (!GetModuleFileName( NULL, szOurPath, MAX_PATH * 2 ))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto CLEAN_UP;
|
|
}
|
|
|
|
// make the path to the .lnk
|
|
TCHAR szTmp[64]; // Used for IDS_BOlnk ("\\boinst.lnk")
|
|
if (0 == LoadString( _Module.m_hInst, IDS_BOlnk, szTmp, sizeof(szTmp)/sizeof(TCHAR) ))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto CLEAN_UP;
|
|
}
|
|
|
|
TCHAR szLinkPath[MAX_PATH + 64];
|
|
if (!SHGetSpecialFolderPath( NULL, szLinkPath, CSIDL_COMMON_STARTUP, FALSE ))
|
|
{
|
|
// MSDN doesn't indicate that SHGetSpecialFolderPath sets GetLastError
|
|
hr = E_FAIL;
|
|
goto CLEAN_UP;
|
|
}
|
|
|
|
_tcscat( szLinkPath, szTmp );
|
|
|
|
// create the startup link
|
|
if (FAILED(hr = MakeLink( szOurPath, szLinkPath, pszNewCmd )))
|
|
goto CLEAN_UP;
|
|
|
|
// run dcpromo.exe with the command line
|
|
// Ensure path is enclosed in quotes
|
|
bstrEXE = _T("\"");
|
|
TCHAR szPath[MAX_PATH] = {0};
|
|
if (0 == GetSystemDirectory(szPath, sizeof(szPath) / sizeof(TCHAR)))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto CLEAN_UP;
|
|
}
|
|
bstrEXE += szPath;
|
|
bstrEXE += _T("dcpromo.exe\"");
|
|
bstrRun = _T("dcpromo.exe /answer:");
|
|
bstrRun += pszDCPromo;
|
|
|
|
USES_CONVERSION;
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
DWORD dwRet;
|
|
memset( &si, 0, sizeof(STARTUPINFO) );
|
|
si.cb = sizeof( STARTUPINFO );
|
|
|
|
if( CreateProcess( (TCHAR*)OLE2T(bstrEXE), (TCHAR*)OLE2T(bstrRun), NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi) )
|
|
{
|
|
do
|
|
{
|
|
dwRet = MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, 100, QS_ALLINPUT);
|
|
if (dwRet == WAIT_OBJECT_0 + 1)
|
|
{
|
|
MSG msg;
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
while (dwRet != WAIT_OBJECT_0 && dwRet != WAIT_FAILED);
|
|
|
|
CloseHandle(pi.hProcess);
|
|
CloseHandle(pi.hThread);
|
|
}
|
|
|
|
CLEAN_UP:
|
|
if (pszDCPromo)
|
|
delete [] pszDCPromo;
|
|
if (pszBOSUnattend)
|
|
delete [] pszBOSUnattend;
|
|
if (pszBOSSetup)
|
|
delete [] pszBOSSetup;
|
|
if (pszNewCmd)
|
|
delete [] pszNewCmd;
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CheckBOSSwitch( TCHAR* pszCmdLine )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComBSTR bstrEXE;
|
|
CComBSTR bstrRun;
|
|
|
|
TCHAR* pszBOSUnattend = NULL;
|
|
TCHAR* pszBOSSetup = NULL;
|
|
|
|
// remove the old .lnk file
|
|
TCHAR szLinkPath[MAX_PATH + 64];
|
|
if ( SHGetSpecialFolderPath(NULL, szLinkPath, CSIDL_COMMON_STARTUP, FALSE) )
|
|
{
|
|
TCHAR szTmp[64];
|
|
LoadString( _Module.m_hInst, IDS_BOlnk, szTmp, sizeof(szTmp)/sizeof(TCHAR) );
|
|
_tcscat( szLinkPath, szTmp );
|
|
DeleteFile( szLinkPath );
|
|
}
|
|
|
|
// look for the switches
|
|
pszBOSUnattend = new TCHAR[_tcslen(pszCmdLine) + 1];
|
|
if (!pszCmdLine)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto CLEAN_UP;
|
|
}
|
|
GetParameter( pszCmdLine, _T("/bosunattend"), pszBOSUnattend );
|
|
|
|
pszBOSSetup = new TCHAR[_tcslen(pszCmdLine) + 1];
|
|
if (!pszBOSSetup)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto CLEAN_UP;
|
|
}
|
|
GetParameter( pszCmdLine, _T("/bossetup"), pszBOSSetup );
|
|
|
|
if( !_tcslen(pszBOSSetup) || !_tcslen(pszBOSUnattend) )
|
|
{
|
|
hr = E_FAIL;
|
|
goto CLEAN_UP;
|
|
}
|
|
|
|
USES_CONVERSION;
|
|
// build the path via the bossetup, the unattend switch, then the unattend file
|
|
bstrEXE = _T("\""); // Ensure path is in quotes
|
|
bstrEXE += T2OLE(pszBOSSetup);
|
|
bstrEXE += _T("\"");
|
|
bstrRun = _T("/unattendfile ");
|
|
bstrRun += T2OLE(pszBOSUnattend);
|
|
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
DWORD dwRet;
|
|
memset( &si, 0, sizeof(STARTUPINFO) );
|
|
si.cb = sizeof( STARTUPINFO );
|
|
|
|
if( CreateProcess( (TCHAR*)OLE2T(bstrEXE), (TCHAR*)OLE2T(bstrRun), NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi) )
|
|
{
|
|
do
|
|
{
|
|
dwRet = MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, 100, QS_ALLINPUT);
|
|
if (dwRet == WAIT_OBJECT_0 + 1)
|
|
{
|
|
MSG msg;
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
while (dwRet != WAIT_OBJECT_0 && dwRet != WAIT_FAILED);
|
|
CloseHandle(pi.hProcess);
|
|
CloseHandle(pi.hThread);
|
|
}
|
|
CLEAN_UP:
|
|
if (pszBOSUnattend)
|
|
delete [] pszBOSUnattend;
|
|
if (pszBOSSetup)
|
|
delete [] pszBOSSetup;
|
|
return hr;
|
|
}
|
|
|
|
VOID GetParameter( TCHAR* pszCmdLine, TCHAR* pszFindSwitch, TCHAR* pszOut )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( pszOut )
|
|
_tcscpy( pszOut, _T("") );
|
|
|
|
if (!pszCmdLine || !pszFindSwitch || !pszOut)
|
|
return;
|
|
|
|
TCHAR* psz = new TCHAR[_tcslen(pszCmdLine) + 1];
|
|
if (!psz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto CLEAN_UP;
|
|
}
|
|
_tcscpy( psz, pszCmdLine );
|
|
_tcslwr( psz );
|
|
|
|
// look for the switch
|
|
TCHAR* pszSwitch = NULL;
|
|
if( !(pszSwitch = _tcsstr(psz, pszFindSwitch)) )
|
|
{
|
|
goto CLEAN_UP;
|
|
}
|
|
|
|
// find the space
|
|
for( ; *pszSwitch && !_istspace(*pszSwitch); ++pszSwitch );
|
|
if( !(*pszSwitch) || !(*(++pszSwitch)) )
|
|
{
|
|
goto CLEAN_UP;
|
|
}
|
|
|
|
// if we have a ", we'll look for the next ", else look for a space
|
|
bool bQuote = false;
|
|
TCHAR* pszStart = pszSwitch;
|
|
if( *pszSwitch == _T('"') )
|
|
{
|
|
bQuote = true;
|
|
++pszSwitch;
|
|
}
|
|
|
|
// inc the pointer until we get either a " or a space
|
|
for( ; *pszSwitch && (bQuote ? (*pszSwitch != _T('"')) : (!_istspace(*pszSwitch))); ++pszSwitch );
|
|
|
|
// if we're at the end and were looking for a quote, fail.
|
|
if( !(*pszSwitch) && bQuote )
|
|
{
|
|
goto CLEAN_UP;
|
|
}
|
|
// if we have a ", inc past it
|
|
else if( bQuote )
|
|
{
|
|
++pszSwitch;
|
|
}
|
|
*pszSwitch = 0;
|
|
_tcscpy( pszOut, pszStart );
|
|
|
|
CLEAN_UP:
|
|
if (psz)
|
|
delete [] psz;
|
|
return;
|
|
|
|
}
|
|
|
|
HRESULT CheckSuppressCYS( TCHAR* pszCmdLine )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!pszCmdLine)
|
|
return E_INVALIDARG;
|
|
|
|
TCHAR* psz = new TCHAR[_tcslen(pszCmdLine) + 1];
|
|
if (!psz)
|
|
return E_OUTOFMEMORY;
|
|
|
|
_tcscpy( psz, pszCmdLine );
|
|
_tcslwr( psz );
|
|
|
|
if( _tcsstr(psz, "/suppresscys") )
|
|
{
|
|
SuppressCfgSrvPage();
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
if (psz)
|
|
delete [] psz;
|
|
return hr;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// DisableBalloons()
|
|
//
|
|
// This function uses the following regkey to disable all balloon messages:
|
|
// HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced
|
|
// EnableBalloonTips = 0x0 or 0x1
|
|
//
|
|
// If bDisable = TRUE, then we disable the balloons (0x0)
|
|
// if bDisable = FALSE, then we enable the balloons (0x1)
|
|
// ----------------------------------------------------------------------------
|
|
VOID DisableBalloons( BOOL bDisable )
|
|
{
|
|
HKEY hk = NULL;
|
|
DWORD dwVal = bDisable ? 0x0 : 0x1;
|
|
|
|
RegCreateKeyEx( HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), NULL, NULL, NULL, KEY_ALL_ACCESS, NULL, &hk, NULL);
|
|
if ( hk )
|
|
{
|
|
if ( RegSetValueEx(hk, _T("EnableBalloonTips"), NULL, REG_DWORD, (BYTE*)&dwVal, sizeof(dwVal)) != ERROR_SUCCESS )
|
|
{
|
|
// ASSERT(FALSE);
|
|
}
|
|
|
|
RegCloseKey(hk);
|
|
}
|
|
}
|
|
|
|
VOID GetSystemDrive(TCHAR** ppszDrive)
|
|
{
|
|
if (!ppszDrive)
|
|
return;
|
|
*ppszDrive = NULL;
|
|
|
|
TCHAR szWindows[MAX_PATH + 1] = {0};
|
|
if (0 != GetWindowsDirectory(szWindows, sizeof(szWindows) / sizeof(TCHAR)))
|
|
{
|
|
*ppszDrive = new TCHAR[MAX_PATH];
|
|
_tsplitpath(szWindows, *ppszDrive, NULL, NULL, NULL);
|
|
|
|
}
|
|
}
|