Click here to Skip to main content
Click here to Skip to main content
Articles » Languages » C++ / CLI » General » Downloads
 
Add your own
alternative version

Enhanced .NET Bootstrap Setup

, 24 Nov 2005
Modified Microsoft Setup program to install required IE6, MSI 2.0 and .NET.
dotnetsetup_exe.zip
setup.exe
settings.ini
dotnetsetup_src.zip
CSingleInstance.hxx
settings.ini
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
/// =======================================================================
// Name    :    main.cpp
// Purpose :    Windows bootstrap application that installs the 
//              Microsoft .Net Framework redistributable files,
//              if necessary, and an additional application msi.

// includes
#include <windows.h>
#include <crtdbg.h>
#include <tchar.h>
#include <stdio.h>
#include <CorError.h>
#include <Shlwapi.h>
#include <WinError.h>
#include <string.h>
#include <direct.h>

#include "CSingleInstance.hxx"  // CSingleInstance implementation
#include "CError.h"             // CError definition
#include "resource.h"           // string defines
#include "SetupCodes.h"         // setup-related error codes
#include "CSettings.h"          // ini-based app globals/settings

#include "main.h"
#include "OSDetector.h"

CSettings g_settings;
DWORD g_dwThread = 0;
HANDLE g_hThread = NULL;
bool test = false;
bool debug = false;
TCHAR szWindowsDir[512];
TCHAR szWindowsSystemDir[512];
TCHAR szMessage[255];                                                                                                                         // procedure
HWND billBoard;
int windowCount = 0;

// ==========================================================================
// WinMain()
//
// Purpose: application entry point
//
// ==========================================================================
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    UINT    uRetCode = 0;       // bootstrapper return code
    BOOL    bFxReboot = FALSE;  // reboot indicated due to fx install
    BOOL    bAppReboot = FALSE; // reboot indicated after host app install
    BOOL    bAppInstallSucceeded = TRUE;

	// Look for a debug flag on the command line
	if (lpCmdLine != NULL)
	{
		if (strstr(lpCmdLine, "/debug") != NULL)
			debug = true;
	}

	// create single instance object
    //
    CSingleInstance si( g_tszBootstrapMutexName );


    // initialize hInstance in global settings
    g_settings.SetHInstance(hInstance);


	try 
    {
        // validate single instance
        //
        // if we are not alone, throw an error
        if( !si.IsUnique() )
        {
			if (debug)
				OutputDebugString("Setup program already running\n");
            CError se( IDS_NOT_SINGLE_INSTANCE, 
                       0, 
                       MB_ICONERROR, 
                       COR_NOT_SINGLE_INSTANCE );

            throw( se );
        }
        // if there was a problem creating mutex, throw an error
        else if( !si.IsHandleOK() )
        {
			if (debug)
				OutputDebugString("Problems creating mutex\n");
            CError se( IDS_SINGLE_INSTANCE_FAIL, 
                       0, 
                       MB_ICONERROR, 
                       COR_SINGLE_INSTANCE_FAIL );

            throw( se );
        }
        
        // parse our application settings
        if (!g_settings.Parse())
        {
			if (debug)
				OutputDebugString("Problems parsing settings file\n");
            CError se( IDS_SETTINGS_INIT_FAILURE, 
                       0, 
                       MB_ICONERROR, 
                       FALSE, 
                       g_settings.GetIniName());

            throw (se);
        }

        // let's be sure we can locate our msi
        // dotnetfx.exe verification occurs later, after
        // the user is queried to confirm setup

        HANDLE handle = CreateFile( g_settings.GetMsi(),
                                    GENERIC_READ,
                                    FILE_SHARE_READ,
                                    NULL, 
                                    OPEN_EXISTING,
                                    FILE_ATTRIBUTE_NORMAL,
                                    NULL);

        if (INVALID_HANDLE_VALUE == handle)
        {
            DWORD dwResult = GetLastError();

            if (ERROR_FILE_NOT_FOUND == dwResult)
            {
				if (debug)
					OutputDebugString("Problems finding msi file\n");
                CError se(IDS_MSI_NOT_FOUND, 
                          0, 
                          MB_ICONERROR, 
                          ERROR_FILE_NOT_FOUND, 
                          g_settings.GetMsi());

                throw (se);
            }
            else
            {
				if (debug)
					OutputDebugString("Problems finding msi file\n");
                CError se( IDS_SETUP_FAILURE, 0, MB_ICONERROR, dwResult);
                throw (se);
            }
        }
        else
        {
            CloseHandle(handle);
        }

		int nResult= 0;

        if (!GetWindowsDirectory(szWindowsDir, LENGTH(szWindowsDir)))
        {
			HandleResult(GetLastError());
        }
        if (!GetSystemDirectory(szWindowsSystemDir, LENGTH(szWindowsSystemDir)))
        {
			HandleResult(GetLastError());
        }

		SetWorkingDir();

		RemoveRegistryRun();
   
		// put ourselves in install mode
        // if running on Terminal Server.
        SetTSInInstallMode();

        DWORD dwResult;

		// Check the OS Version
		PLATFORM platform = getPlatform();

		checkIE();
		//checkMSI();
		MSINeedsInstalling = false;
		checkMDAC();
		checkMSDE();
		checkDotNetServicePack();
		checkExtraProgram1();

		DotNetINeedsInstalling = FxInstallRequired() == ERROR_SUCCESS ? false : true;

		// If one of the 3 needed components needs installing, show the install dialog
		if (test || (DotNetINeedsInstalling || IENeedsInstalling || MSINeedsInstalling || MDACNeedsInstalling || MSDENeedsInstalling))
		{
			if (debug)
				OutputDebugString("Need to install something. Bringing up dialog box\n");
			if (DialogBox(hInstance, MAKEINTRESOURCE(IDD_INSTALL), NULL, DlgProc) != TRUE)
				return 0;
		}

		if (IENeedsInstalling)
		{
/*
			::LoadString( g_settings.GetHInstance(), 
						IDS_IE_INSTALL, 
						szMessage, 
						LENGTH(szMessage) ) ;

			setBillBoardText(szMessage);
*/
			if (debug)
				OutputDebugString("IE needs to be installed\n");
			// now we install the ie6 installer
			// 2 add'l chars for zero-term and 
			// space embedded between msi name & cmd-line
			// MAX_PATH+1 is the storage allocated for the msi path/name
			TCHAR szIEInstallCmd[ MAX_PATH + LENGTH(g_tszIE6) + 2];

			// build msi cmd-line
			// note that we inject the Msi name
			// into the cmd-line

			_sntprintf( szIEInstallCmd, 
						LENGTH(szIEInstallCmd)-1, 
						g_tszIE6, 
						g_settings.GetIEPath());

			dwResult = runExe(szIEInstallCmd);
			// Problems installing
			if (HandleResult(dwResult) == false)
			{
				return dwResult;
			}
			bAppReboot = Reboot(dwResult);
			
			if (bAppReboot)
			{
				InsertRegistryRun();
				CError se( IDS_REBOOT_REQUIRED, IDS_DIALOG_CAPTION, MB_YESNO);

				nResult = se.ShowMessage();

				if (nResult == IDYES)
				{
					InitiateReboot();
				}
				else
				{
					return uRetCode;
				}
			}

		}

		if (MDACNeedsInstalling)
		{

			ShowBillboard(&g_dwThread, &g_hThread);	
	
			::LoadString( g_settings.GetHInstance(), 
						IDS_MDAC_INSTALL, 
						szMessage, 
						LENGTH(szMessage) ) ;

			setBillBoardText(szMessage);
			if (debug)
				OutputDebugString("MDAC needs to be installed\n");

			// now we install the mdac installer
			// 2 add'l chars for zero-term and 
			// space embedded between msi name & cmd-line
			// MAX_PATH+1 is the storage allocated for the msi path/name
			TCHAR szMDACInstallCmd[ MAX_PATH + LENGTH(g_tszMDACCmdLine) + 2];

			// build msi cmd-line
			// note that we inject the Msi name
			// into the cmd-line

			_sntprintf( szMDACInstallCmd, 
						LENGTH(szMDACInstallCmd)-1, 
						g_tszMDACCmdLine, 
						g_settings.GetMDACPath());

			dwResult = runExe(szMDACInstallCmd);
			TeardownBillboard(g_dwThread, g_hThread);
			// Problems installing
			if (HandleResult(dwResult) == false)
			{
				return dwResult;
			}
			bAppReboot = Reboot(dwResult) ? true : bAppReboot;
		}


		// MSDE - Has it's own installer - don't display billboard
		if (MSDENeedsInstalling)
		{
/*
			::LoadString( g_settings.GetHInstance(), 
						IDS_MSDE_INSTALL, 
						szMessage, 
						LENGTH(szMessage) ) ;

			setBillBoardText(szMessage);
*/
			if (debug)
				OutputDebugString("MSDE needs to be installed\n");

			// now we install the MSDE installer
			// 2 add'l chars for zero-term and 
			// space embedded between msi name & cmd-line
			// MAX_PATH+1 is the storage allocated for the msi path/name
			TCHAR szMSDEInstallCmd[ MAX_PATH + LENGTH(g_tszMSDECmdLine) + 2];

			// build msi cmd-line
			// note that we inject the Msi name
			// into the cmd-line

			_sntprintf( szMSDEInstallCmd, 
						LENGTH(szMSDEInstallCmd)-1, 
						g_tszMSDECmdLine, 
						g_settings.GetMSDEPath(), g_settings.GetMSDEParams());

			dwResult = runExe(szMSDEInstallCmd);
			// Problems installing
			if (HandleResult(dwResult) == false)
			{
				return dwResult;
			}
			bAppReboot = Reboot(dwResult) ? true : bAppReboot;

		}


		if (MSINeedsInstalling && (platform != PLATFORM_WIN32_XP))
		{
			if (debug)
				OutputDebugString("MSI needs to be installed\n");
			// now we install the msi installer
			// 2 add'l chars for zero-term and 
			// space embedded between msi name & cmd-line
			// MAX_PATH+1 is the storage allocated for the msi path/name
			TCHAR szMsiInstallCmd[ MAX_PATH + LENGTH(g_tszMSI98) + 2];

			// build msi cmd-line
			// note that we inject the Msi name
			// into the cmd-line

			if (platform == PLATFORM_WIN32)
				_sntprintf( szMsiInstallCmd, 
							LENGTH(szMsiInstallCmd)-1, 
							g_tszMSI98, 
							g_settings.GetMSIPath());
			else
				_sntprintf( szMsiInstallCmd, 
							LENGTH(szMsiInstallCmd)-1, 
							g_tszMSINT, 
							g_settings.GetMSIPath());

			dwResult = runExe(szMsiInstallCmd);
			// Problems installing
			if (HandleResult(dwResult) == false)
			{
				return dwResult;
			}
			bAppReboot = Reboot(dwResult) ? true : bAppReboot;
		}

		if (ExtraProgramPath1NeedsInstalling)
		{
			LPCTSTR programPath = g_settings.GetExtraProgramPath1();
			LPCTSTR programOptions = g_settings.GetExtraProgramPathOptions1();
			TCHAR szExtraProgramInstallCmd[ MAX_PATH + LENGTH(programPath) + LENGTH(programOptions) + 2];
			_sntprintf( szExtraProgramInstallCmd, 
						LENGTH(szExtraProgramInstallCmd) - 1, 
						_T("%s %s"), programPath, 
						programOptions);

			dwResult = runExe(szExtraProgramInstallCmd);
			// Problems installing
			if (HandleResult(dwResult) == false)
			{
				return dwResult;
			}
			bAppReboot = Reboot(dwResult) ? true : bAppReboot;
		}

		// install Fx if required
        if (DotNetINeedsInstalling)
        {
			LPCTSTR options = g_settings.GetFxInstallerOptions();
			// Are we running in quiet mode?
			if (strstr(options, "/q") != NULL)
			{
				ShowBillboard(&g_dwThread, &g_hThread);	

				::LoadString( g_settings.GetHInstance(), 
							IDS_FX_INSTALL, 
							szMessage, 
							LENGTH(szMessage) ) ;

				setBillBoardText(szMessage);
			}

			if (debug)
				OutputDebugString(".Net needs to be installed\n");
            DWORD dwResult;

            // 2 add'l chars for zero-term and 
            // space embedded between app name & cmd-line
            TCHAR szFxInstallCmd[MAX_PATH + 
                                 LENGTH(g_tszFxInstaller) + 
                                 LENGTH(g_settings.GetFxInstallerOptions())+ 2];//LENGTH(g_tszFxInstallerCmdLine)+ 2];

            // build fully-qualified path to dotnetfx.exe

            _sntprintf( szFxInstallCmd, 
                        LENGTH(szFxInstallCmd)-1, 
                        _T("%s%s %s"), 
                        g_settings.GetFxInstallerPath(),
                        g_tszFxInstaller,
                        g_settings.GetFxInstallerOptions());//g_tszFxInstallerCmdLine);


            // execute dotnetfx.exe setup
            dwResult = runExe(szFxInstallCmd);
			// Are we running in quiet mode?
			if (strstr(options, "/q") != NULL)
			{
				TeardownBillboard(g_dwThread, g_hThread);
			}
            
            if ( ERROR_SUCCESS_REBOOT_REQUIRED == dwResult ||
                ERROR_SUCCESS == dwResult )
            {
                //bFxReboot = (dwResult == ERROR_SUCCESS_REBOOT_REQUIRED);
				bFxReboot = true;
            } 
            else 
            {
                switch(dwResult)
                {
					case 8192: // Reboot
						bFxReboot = true;
						break;

					case 4096: 
					{
                        CError se( IDS_ERROR1, 
                                   0, 
                                   MB_ICONERROR, 
                                   dwResult );

                        throw ( se );
                        break ;
					}
					case 4097: 
					{
                        CError se( IDS_ERROR2, 
                                   0, 
                                   MB_ICONERROR, 
                                   dwResult );

                        throw ( se );
                        break ;
					}
					case 4098: 
					{
                        CError se( IDS_ERROR3, 
                                   0, 
                                   MB_ICONERROR, 
                                   dwResult );

                        throw ( se );
                        break ;
					}
					case 4099: 
					{
                        CError se( IDS_ERROR4, 
                                   0, 
                                   MB_ICONERROR, 
                                   dwResult );

                        throw ( se );
                        break ;
					}
					case 4100: 
					{
                        CError se( IDS_ERROR5, 
                                   0, 
                                   MB_ICONERROR, 
                                   dwResult );

                        throw ( se );
                        break ;
					}
					case 4101: 
					{
                        CError se( IDS_ERROR6, 
                                   0, 
                                   MB_ICONERROR, 
                                   dwResult );

                        throw ( se );
                        break ;
					}
					case 4104: 
					{
                        CError se( IDS_ERROR7, 
                                   0, 
                                   MB_ICONERROR, 
                                   dwResult );

                        throw ( se );
                        break ;
					}

					case 4111: 
					{
                        CError se( IDS_ERROR8, 
                                   0, 
                                   MB_ICONERROR, 
                                   dwResult );

                        throw ( se );
                        break ;
					}
					case 4113: 
					{
                        CError se( IDS_ERROR9, 
                                   0, 
                                   MB_ICONERROR, 
                                   dwResult );

                        throw ( se );
                        break ;
					}
					case 4114: 
					{
                        CError se( IDS_ERROR10, 
                                   0, 
                                   MB_ICONERROR, 
                                   dwResult );

                        throw ( se );
                        break ;
					}
					case 8191: 
					{
                        CError se( IDS_ERROR5, 
                                   0, 
                                   MB_ICONERROR, 
                                   dwResult );

                        throw ( se );
                        break ;
					}


                    default :
                    {
                        CError se( IDS_SETUP_FAILURE, 
                                   0, 
                                   MB_ICONERROR, 
                                   dwResult );

                        throw ( se );
                        break ;
                    }
                }
            }
        }
		// install Fx FxServicePackNeedsInstalling required
        if (FxServicePackNeedsInstalling)
        {
			LPCTSTR servicePackPath = g_settings.GetFxServicePack();
			dwResult = runExe(servicePackPath);
			// Problems installing
			if (HandleResult(dwResult) == false)
			{
				return dwResult;
			}
			bAppReboot = Reboot(dwResult) ? true : bAppReboot;
		}


		// now we install the host msi


        // 2 add'l chars for zero-term and 
        // space embedded between msi name & cmd-line
        // MAX_PATH+1 is the storage allocated for the msi path/name
        TCHAR szMsiInstallCmd[ MAX_PATH + LENGTH(g_tszMsiCmdLine) + 2];

        // build msi cmd-line
        // note that we inject the Msi name
        // into the cmd-line

        _sntprintf( szMsiInstallCmd, 
                    LENGTH(szMsiInstallCmd)-1,
                    g_tszMsiCmdLine, 
					szWindowsSystemDir,
                    g_settings.GetMsi());


		if (debug)
			OutputDebugString("Now running main installer\n");
		dwResult = ExecCmd(szMsiInstallCmd);

        if ( ERROR_SUCCESS_REBOOT_REQUIRED == dwResult ||
            ERROR_SUCCESS == dwResult )
        {
            bAppReboot = (dwResult == ERROR_SUCCESS_REBOOT_REQUIRED) ? true : bAppReboot;
        } 
        else if ( dwResult == ERROR_INSTALL_USEREXIT)
		{
            bAppInstallSucceeded = FALSE;
		}
        else 
        {
			if (debug)
				OutputDebugString("Problems running installer\n");
            // we display the error msg here and do not rethrow
            // this is because we need to continue with a system
            // reboot in the event that fx was installed 
            // successfully before msi-install failure
            CError se( IDS_SETUP_FAILURE, 0, MB_ICONERROR, dwResult );
            se.ShowMessage();
            bAppInstallSucceeded = FALSE;
        }

        // now handle the reboot

        if (bFxReboot || bAppReboot)
        {
			if (debug)
				OutputDebugString("Rebooting\n");
            CError se( IDS_REBOOT_QUERY, IDS_DIALOG_CAPTION, MB_YESNO);

            nResult = se.ShowMessage();

            if (nResult == IDYES)
            {
				InsertRegistryRun();
                InitiateReboot();
            }
        }
        else
        {
            // we only throw up the setup succeeded dialog
            // if the app install was successful. 
/*
            if (bAppInstallSucceeded)
            {
				if (debug)
					OutputDebugString("Application installed successfully\n");
                CError se( IDS_SETUP_SUCCEEDED, IDS_DIALOG_CAPTION, MB_OK );
                se.ShowMessage();
            }
*/
        }
    }

    catch (HRESULT)
    {
        // hresult exception msg display is handled
        // by the originator. the exception is rethrown
        // and caught here in order to exit.
    }

    catch( CError se )
    {
        uRetCode = se.m_nRetCode;
        se.ShowMessage();
    }

    catch( ... )
    {
        CError se( IDS_SETUP_FAILURE, 0, MB_ICONERROR, COR_EXIT_FAILURE );
        uRetCode = se.m_nRetCode;
        se.ShowMessage();
    }

    return uRetCode;
}

BOOL Reboot(DWORD dwResult)
{
    if ( ERROR_SUCCESS_REBOOT_REQUIRED == dwResult ||
        ERROR_SUCCESS == dwResult )
    {
        return (dwResult == ERROR_SUCCESS_REBOOT_REQUIRED);
    } 
	return false;
}
BOOL HandleResult(DWORD dwResult)
{
    if ( ERROR_SUCCESS_REBOOT_REQUIRED == dwResult ||
        ERROR_SUCCESS == dwResult )
    {
        return true;
    } 
    else 
    {
        // we display the error msg here and do not rethrow
        // this is because we need to continue with a system
        // reboot in the event that fx was installed 
        // successfully before msi-install failure
        CError se( IDS_SETUP_FAILURE, 0, MB_ICONERROR, dwResult );
        se.ShowMessage();
		return false;
    }
	return true;
}

// ==========================================================================
// ExecCmd()
//
// Purpose:
//  Executes command-line
// Inputs:
//  LPCTSTR pszCmd: command to run
// Outputs:
//  DWORD dwExitCode: exit code from the command
// Notes: This routine does a CreateProcess on the input cmd-line
//        and waits for the launched process to exit.
// ==========================================================================
DWORD ExecCmd( LPCTSTR pszCmd )
{
    BOOL  bReturnVal   = false ;
    STARTUPINFO  si ;
    DWORD  dwExitCode ;
    SECURITY_ATTRIBUTES saProcess, saThread ;
    PROCESS_INFORMATION process_info ;

    ZeroMemory(&si, sizeof(si)) ;
    si.cb = sizeof(si) ;

    saProcess.nLength = sizeof(saProcess) ;
    saProcess.lpSecurityDescriptor = NULL ;
    saProcess.bInheritHandle = TRUE ;

    saThread.nLength = sizeof(saThread) ;
    saThread.lpSecurityDescriptor = NULL ;
    saThread.bInheritHandle = FALSE ;

    bReturnVal = CreateProcess(NULL, 
                               (LPTSTR)pszCmd, 
                               &saProcess, 
                               &saThread, 
                               FALSE, 
                               DETACHED_PROCESS, 
                               NULL, 
                               NULL, 
                               &si, 
                               &process_info) ;

    if (bReturnVal)
    {
        CloseHandle( process_info.hThread ) ;
        WaitForSingleObject( process_info.hProcess, INFINITE ) ;
        GetExitCodeProcess( process_info.hProcess, &dwExitCode ) ;
        CloseHandle( process_info.hProcess ) ;
    }
    else
    {
        CError se( IDS_CREATE_PROCESS_FAILURE, 
                   0, 
                   MB_ICONERROR, 
                   COR_EXIT_FAILURE, 
                   pszCmd );

        throw( se );
    }

    return dwExitCode;
}

// ==========================================================================
// FxInstallRequired()
//
// Purpose:
//  Checks whether the provided Microsoft .Net Framework redistributable
//  files should be installed to the local machine
//
// ==========================================================================
BOOL FxInstallRequired()
{
    BOOL bResult = TRUE;

    TCHAR szFxInstaller[MAX_PATH + LENGTH(g_tszFxInstaller)];

    // build fully-qualified path to dotnetfx.exe

    _sntprintf( szFxInstaller, 
                LENGTH(szFxInstaller)-1, 
                _T("%s%s"), 
                g_settings.GetFxInstallerPath(),
                g_tszFxInstaller);

    try 
    {
        HRESULT hr;
        VS_FIXEDFILEINFO vsf;

        hr = GetFileVersion (szFxInstaller, &vsf);

        if (FAILED(hr))
        {
            throw hr;
        }

        // retrieve dotnetfx.exe build #
        //
        DWORD dwFileVersionLS = vsf.dwFileVersionLS >> 16;

        // we need a text representation 
        //
        TCHAR szVersion[11]; // sufficient for DWORD max + zero term

        _stprintf( szVersion, 
                   _T("%u"), 
                   dwFileVersionLS);

        // now we'll check the registry for this value
        //
        LONG lResult;
        HKEY hkey = NULL;

		// Append the version to the key
		TCHAR szFxRegKey[MAX_PATH+1];

        sprintf( szFxRegKey, "%s%s", g_tszFxRegKey, g_settings.GetNetVersion());
		
        
        lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, // handle to open key
                                szFxRegKey,      // name of subkey to open
                                NULL,
                                KEY_READ,
                                &hkey               // handle to open key
                                );

		// we don't proceed unless the call above succeeds
        if (ERROR_FILE_NOT_FOUND == lResult)
        {
//			MessageBox(NULL, "Couldn't find .Net Key", "Error", MB_OK | MB_ICONINFORMATION);
			if (debug)
				OutputDebugString("Could not find .Net Key\n");
            return ERROR_FILE_NOT_FOUND;
        }


        if (ERROR_SUCCESS == lResult)
        {
            TCHAR szPolicy[256];
            DWORD dwBufLen = LENGTH(szPolicy);

            lResult = RegQueryValueEx( hkey,
                                    szVersion,
                                    NULL,
                                    NULL,
                                    (LPBYTE)szPolicy,
                                    &dwBufLen);
            
            if (ERROR_SUCCESS == lResult)
            {
                // key found, now we need to check for the existence of
                // the appropriate language install dir.  
                

                strncat(szWindowsDir, 
                        _T("\\Microsoft.Net\\Framework\\"), 
                        LENGTH(szWindowsDir));

                strncat(szWindowsDir, 
                        g_settings.GetNetVersion(), 
                        LENGTH(szWindowsDir));
     
				strncat(szWindowsDir, 
                        _T("."), 
                        LENGTH(szWindowsDir));

                strncat(szWindowsDir, 
                        szVersion, 
                        LENGTH(szWindowsDir));

                strncat(szWindowsDir, 
                        _T("\\"), 
                        LENGTH(szWindowsDir));

                strncat(szWindowsDir, 
                        g_settings.GetLanguageDirectory(), 
                        LENGTH(szWindowsDir));

                DWORD dwResult = GetFileAttributes(szWindowsDir);

                if (dwResult != INVALID_FILE_ATTRIBUTES && 
                    (dwResult & FILE_ATTRIBUTE_DIRECTORY))
                {   
                    // we found our subdirectory, no need to install
                    bResult = FALSE;
                }
            }
            // if we receive an error other than 0x2, throw
            else if (ERROR_FILE_NOT_FOUND != lResult)
            {
				if (debug) {
					sprintf(szMessage, "Problems finding %s", szVersion);
					OutputDebugString(szMessage);
				}
                RegCloseKey(hkey);
                throw HRESULT_FROM_WIN32(lResult);
            }
			else
			{
				LPVOID lpMsgBuf;
				FormatMessage( 
					FORMAT_MESSAGE_ALLOCATE_BUFFER | 
					FORMAT_MESSAGE_FROM_SYSTEM | 
					FORMAT_MESSAGE_IGNORE_INSERTS,
					NULL,
					lResult,
					MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
					(LPTSTR) &lpMsgBuf,
					0,
					NULL );
				// Display the string.
//				MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
				MessageBox( NULL, "Could not find the .Net Version Number in the registry", "Error", MB_OK | MB_ICONINFORMATION );
			}

            RegCloseKey(hkey);
        }
    }

    catch( HRESULT hr )
    {
        CError se;

        se.ShowHResultMessage(IDS_VERSION_DETECT_FAILED, 
                              0, 
                              MB_OK, 
                              hr, 
                              szFxInstaller);

        throw hr;
    }
	if (debug)
	{
		if (bResult)
			OutputDebugString(".Net needs to be installed\n");
		else
			OutputDebugString(".Net does not need to be installed\n");
	}

	if (test)
		return FALSE;
    return bResult;
}

// ==========================================================================
// GetFileVersion()
//
// Purpose: retrieves a file version info structure for the specified file
//
// ==========================================================================
HRESULT GetFileVersion (LPTSTR filename, VS_FIXEDFILEINFO *pvsf) 
{
    DWORD dwHandle;
    HRESULT hrReturn = S_OK;
    char* pver = NULL;

    try 
    {
        DWORD cchver = GetFileVersionInfoSize(filename,&dwHandle);
        if (cchver == 0)
        {
            throw LastError();
        }
        pver = new char[cchver];

        if (!pver)
        {
            throw E_OUTOFMEMORY;
        }

        BOOL bret = GetFileVersionInfo(filename,dwHandle,cchver,pver);
        if (!bret) 
        {
            throw LastError();
        }
        UINT uLen;
        void *pbuf;
        bret = VerQueryValue(pver,_T("\\"),&pbuf,&uLen);
        if (!bret) 
        {
            throw LastError();
        }
        memcpy(pvsf,pbuf,sizeof(VS_FIXEDFILEINFO));
    }
    catch (HRESULT hr)
    {
        hrReturn = hr;
    }

    delete[] pver;
    return hrReturn;
}

HRESULT LastError () 
{
   HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
   if (SUCCEEDED(hr))
   {
      hr = E_FAIL;
   }
   return hr;
}

// ==========================================================================
// InitiateReboot()
//
// Purpose: initiates a system reboot
//
// ==========================================================================
BOOL InitiateReboot()
{
/*
    HANDLE hToken;              // handle to process token 
    TOKEN_PRIVILEGES tkp;       // pointer to token structure     
     
    try 
    {
        // Get the current process token handle so we can get shutdown 
        // privilege. 
         
        if (!OpenProcessToken(GetCurrentProcess(), 
                TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
        {
            return FALSE;
        }
         
        // Get the LUID for shutdown privilege. 
         
        LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, 
                &tkp.Privileges[0].Luid); 
         
        tkp.PrivilegeCount = 1;  // one privilege to set    
        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
         
        // Get shutdown privilege for this process. 
         
        AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, 
            (PTOKEN_PRIVILEGES) NULL, 0); 
         
        // Cannot test the return value of AdjustTokenPrivileges. 
         
        if (GetLastError() != ERROR_SUCCESS) 
        {
            return FALSE;
        }
    }

    catch (...)
    {
    }
	*/
#if(_WIN32_WINNT >= 0x0500)
    return ExitWindowsEx( EWX_REBOOT, EWX_FORCEIFHUNG);
#else
    return ExitWindowsEx( EWX_REBOOT, 0);
#endif /* _WIN32_WINNT >= 0x0500 */
}

// ==========================================================================
// SetTSInInstallMode()
//
// Purpose: checks if Terminal Services is enabled and if so
//          switches machine to INSTALL mode
// ==========================================================================
void SetTSInInstallMode()
{
    if (IsTerminalServicesEnabled())
    {
        ExecCmd(g_tszTSChangeUserToInstall);
    }
}

//Detecting If Terminal Services is Installed
// code is taken directly from  
// http://msdndevstg/library/psdk/termserv/termserv_7mp0.htm


/* -------------------------------------------------------------
   Note that the ValidateProductSuite and IsTerminalServices
   functions use ANSI versions of Win32 functions to maintain
   compatibility with Windows 95/98.
   ------------------------------------------------------------- */

BOOL IsTerminalServicesEnabled() 
{
  BOOL    bResult = FALSE;
  DWORD   dwVersion;
  OSVERSIONINFOEXA osVersion;
  DWORDLONG dwlCondition = 0;
  HMODULE hmodK32 = NULL;
  HMODULE hmodNtDll = NULL;
  typedef ULONGLONG (WINAPI *PFnVerSetCondition) (ULONGLONG, ULONG, UCHAR);
  typedef BOOL (WINAPI *PFnVerifyVersionA) (POSVERSIONINFOEXA, DWORD, DWORDLONG);
  PFnVerSetCondition pfnVerSetCondition;
  PFnVerifyVersionA pfnVerifyVersionA;

  dwVersion = GetVersion();

  // Are we running Windows NT?

  if (!(dwVersion & 0x80000000)) 
  {
    // Is it Windows 2000 or greater?
    
    if (LOBYTE(LOWORD(dwVersion)) > 4) 
    {
      // In Windows 2000, use the VerifyVersionInfo and 
      // VerSetConditionMask functions. Don't static link because 
      // it won't load on earlier systems.

      hmodNtDll = GetModuleHandleA( "ntdll.dll" );
      if (hmodNtDll) 
      {
        pfnVerSetCondition = (PFnVerSetCondition) GetProcAddress( 
            hmodNtDll, "VerSetConditionMask");
        if (pfnVerSetCondition != NULL) 
        {
          dwlCondition = (*pfnVerSetCondition) (dwlCondition, 
              VER_SUITENAME, VER_AND);

          // Get a VerifyVersionInfo pointer.

          hmodK32 = GetModuleHandleA( "KERNEL32.DLL" );
          if (hmodK32 != NULL) 
          {
            pfnVerifyVersionA = (PFnVerifyVersionA) GetProcAddress(
               hmodK32, "VerifyVersionInfoA") ;
            if (pfnVerifyVersionA != NULL) 
            {
              ZeroMemory(&osVersion, sizeof(osVersion));
              osVersion.dwOSVersionInfoSize = sizeof(osVersion);
              osVersion.wSuiteMask = VER_SUITE_TERMINAL;
              bResult = (*pfnVerifyVersionA) (&osVersion,
                  VER_SUITENAME, dwlCondition);
            }
          }
        }
      }
    }
    else  // This is Windows NT 4.0 or earlier.

      bResult = ValidateProductSuite( "Terminal Server" );
  }

  return bResult;
}


// ==========================================================================
// ValidateProductSuite()
//
// Purpose:
//  Terminal Services detection code for systems running
//  Windows NT 4.0 and earlier.
// ==========================================================================
BOOL ValidateProductSuite (LPSTR lpszSuiteToValidate) 
{
  BOOL fValidated = FALSE;
  LONG lResult;
  HKEY hKey = NULL;
  DWORD dwType = 0;
  DWORD dwSize = 0;
  LPSTR lpszProductSuites = NULL;
  LPSTR lpszSuite;

  // Open the ProductOptions key.

  lResult = RegOpenKeyA(
      HKEY_LOCAL_MACHINE,
      "System\\CurrentControlSet\\Control\\ProductOptions",
      &hKey
  );
  if (lResult != ERROR_SUCCESS)
      goto exit;

  // Determine required size of ProductSuite buffer.

  lResult = RegQueryValueExA( hKey, "ProductSuite", NULL, &dwType, 
      NULL, &dwSize );
  if (lResult != ERROR_SUCCESS || !dwSize)
      goto exit;

  // Allocate buffer.

  lpszProductSuites = (LPSTR) LocalAlloc( LPTR, dwSize );
  if (!lpszProductSuites)
      goto exit;

  // Retrieve array of product suite strings.

  lResult = RegQueryValueExA( hKey, "ProductSuite", NULL, &dwType,
      (LPBYTE) lpszProductSuites, &dwSize );
  if (lResult != ERROR_SUCCESS || dwType != REG_MULTI_SZ)
      goto exit;

  // Search for suite name in array of strings.

  lpszSuite = lpszProductSuites;
  while (*lpszSuite) 
  {
      if (lstrcmpA( lpszSuite, lpszSuiteToValidate ) == 0) 
      {
          fValidated = TRUE;
          break;
      }
      lpszSuite += (lstrlenA( lpszSuite ) + 1);
  }

exit:
  if (lpszProductSuites)
      LocalFree( lpszProductSuites );

  if (hKey)
      RegCloseKey( hKey );

  return fValidated;
}

// ==========================================================================
// ShowBillboard()
//
// Purpose:
//  Display billboard on created thread
// ==========================================================================
void ShowBillboard(DWORD * pdwThreadId, HANDLE * phThread)
{
	if (windowCount != 0)
		return;

	HANDLE threadEvent = CreateEvent( 
        NULL,     // no security attributes
        FALSE,    // auto-reset event
        FALSE,     // initial state is not signaled
        NULL);    // object not named


	*phThread = CreateThread(NULL, 
                            0L, 
                            StaticThreadProc, 
                            (LPVOID)&threadEvent, 
                            0, 
                            pdwThreadId );
    // Wait for any message sent or posted to this queue 
    // or for one of the passed handles be set to signaled.
	// This is important as the window does not get created until
	// the StaticThreadProc gets called
	HANDLE handles[1];
	handles[0] = threadEvent;
    DWORD result = WaitForMultipleObjects(1, handles, FALSE, INFINITE); 
}

// ==========================================================================
// TeardownBillboard()
//
// Purpose:
//  Take down billboard
// ==========================================================================
void TeardownBillboard(DWORD dwThreadId, HANDLE hThread)
{
	if (windowCount != 1 || hThread == NULL)
		return;
    //    Tell the thread to destroy the modeless dialog

    while (!(PostThreadMessage( dwThreadId, PWM_THREADDESTROYWND, 0, 0 )))
	{
		Sleep(5);
	}
    WaitForSingleObject( hThread, INFINITE );

    CloseHandle( hThread );
	hThread = NULL;
	windowCount = 0;
}

// ==========================================================================
// StaticThreadProc()
//
// Purpose:
//  Thread proc that creates our billboard dialog
// ==========================================================================
DWORD WINAPI StaticThreadProc( LPVOID lpParameter )
{
    MSG msg;
    HANDLE startEvent = *(HANDLE*)lpParameter;  // thread's read event

	// Create the billboard dialog up front so we can change the text
	billBoard = CreateDialog(g_settings.GetHInstance(), 
						MAKEINTRESOURCE(IDD_BILLBOARD), 
						GetDesktopWindow(), 
						BillboardProc);

    ShowWindow(billBoard, SW_SHOW); 
	windowCount = 1;
	SetEvent(startEvent); // Signal event

    while( GetMessage( &msg, NULL, 0, 0 ) )
    {
        if (!::IsDialogMessage( billBoard, &msg ))
        {
            if (msg.message == PWM_THREADDESTROYWND)
            {
                //    Tell the dialog to destroy itself
                DestroyWindow(billBoard);

                //    Tell our thread to break out of message pump
                PostThreadMessage( g_dwThread, WM_QUIT, 0, 0 );
            }
        }
    } 

    return( 0L );
}

// ==========================================================================
// BillboardProc()
//
// Purpose:
//  Callback proc used to set HWND_TOPMOST on billboard
// ==========================================================================
BOOL CALLBACK BillboardProc(HWND hwndDlg, 
                            UINT message, 
                            WPARAM wParam, 
                            LPARAM lParam) 
{ 
    switch (message) 
    { 
        case WM_INITDIALOG: 
            SetWindowPos( hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
            return TRUE;
    } 
    return FALSE; 
} 

// Return the index of the search string
size_t getStringIndex(char *searchStr, char *searchFor)
{
	size_t searchLen = strlen(searchStr);
	size_t forLen = strlen(searchFor);
	for (size_t i=0; i < searchLen; i++)
	{
		if (searchStr[i] != searchFor[0])
			continue;
		bool found = false;
		for (size_t j=0; j < forLen; j++)
		{
			found = false;
			if (i+j > searchLen)
				break;
			if (searchStr[i+j] != searchFor[j])
				break;
			found = true;
		}
		if (found)
			return i;
	}
	return -1;
}

void checkIE()
{
	// now we'll check the registry for this value
	//
	LONG lResult;
	HKEY hkey = NULL;
	
	lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, // handle to open key
							g_tszIERegKey,      // name of subkey to open
							NULL,
							KEY_READ,
							&hkey               // handle to open key
							);

	// we don't proceed unless the call above succeeds
	if (ERROR_SUCCESS != lResult && ERROR_FILE_NOT_FOUND != lResult)
	{
		if (debug) {
			sprintf(szMessage, "Could not find key for %s", g_tszIERegKey);
			OutputDebugString(szMessage);
		}
		IENeedsInstalling = true;
		return;
//		throw HRESULT_FROM_WIN32(lResult);
	}

	if (ERROR_SUCCESS == lResult)
	{
		TCHAR szVersion[256];
		DWORD dwBufLen = LENGTH(szVersion);

		lResult = RegQueryValueEx( hkey,
								g_tszIERegKeyValue,
								NULL,
								NULL,
								(LPBYTE)szVersion,
								&dwBufLen);
	    
		if (ERROR_SUCCESS == lResult)
		{
			char majorVersionStr[2], minorVersionStr[2];
			majorVersionStr[0] = szVersion[0];
			majorVersionStr[1] = '\0';
			minorVersionStr[0] = szVersion[2];
			minorVersionStr[1] = '\0';
			int majorVersion = atoi(majorVersionStr);
			int minorVersion = atoi(minorVersionStr);
			if (majorVersion < 5 || (majorVersion == 5 && minorVersion < 1))
				IENeedsInstalling = true;
		}
		// if we receive an error other than 0x2, throw
		else if (ERROR_FILE_NOT_FOUND != lResult)
		{
			if (debug) {
				sprintf(szMessage, "Could not find key for %s", g_tszIERegKeyValue);
				OutputDebugString(szMessage);
			}
			RegCloseKey(hkey);
			throw HRESULT_FROM_WIN32(lResult);
		}

		RegCloseKey(hkey);
	}
	if (debug)
	{
		if (IENeedsInstalling)
			OutputDebugString("IE needs to be installed\n");
		else
			OutputDebugString("IE does not need to be installed\n");
	}
	if (test)
		IENeedsInstalling = true;
}

/**
Method to check to see if Microsoft's 2.0 installer needs to be installed
*/
void checkMSI()
{
	// now we'll check the registry for this value
	//
	LONG lResult;
	HKEY hkey = NULL;
	
	lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, // handle to open key
							g_tszMSIRegKey,      // name of subkey to open
							NULL,
							KEY_READ,
							&hkey               // handle to open key
							);

	// we don't proceed unless the call above succeeds
	if ((ERROR_SUCCESS != lResult) || (ERROR_FILE_NOT_FOUND == lResult))
	{
		if (debug) {
			sprintf(szMessage, "Could not find key %s", g_tszMSIRegKey);
			OutputDebugString(szMessage);
		}
		throw HRESULT_FROM_WIN32(lResult);
	}

	TCHAR szLocation[256];
	if (ERROR_SUCCESS == lResult)
	{
		DWORD dwBufLen = LENGTH(szLocation);

		lResult = RegQueryValueEx( hkey,
								g_tszMSIRegKeyValue,
								NULL,
								NULL,
								(LPBYTE)szLocation,
								&dwBufLen);
	    
		// if we receive an error other than 0x2, throw
		if (ERROR_SUCCESS == lResult)
		{
		}
		else if (ERROR_FILE_NOT_FOUND != lResult)
		{
			if (debug) {
				sprintf(szMessage, "Could not find key value %s", g_tszMSIRegKeyValue);
				OutputDebugString(szMessage);
			}
//			MessageBox(NULL, "Did not Find MSI", "Error", MB_OK | MB_ICONINFORMATION);
			RegCloseKey(hkey);
			throw HRESULT_FROM_WIN32(lResult);
		}

		RegCloseKey(hkey);
	}
	strcat(szLocation, "\\msiexec.exe");
//	MessageBox(NULL, "Found MSI", szLocation, MB_OK | MB_ICONINFORMATION);

	//Find out how much space we need to store the version 
	//information block.
	DWORD dwVersionInfoSize;
	DWORD dwZero; //Temp variable.
	dwVersionInfoSize = GetFileVersionInfoSize(szLocation, &dwZero);
	if (dwVersionInfoSize)
	{
		//Allocate space to store the version info.
		void* pVersionInfo = malloc(dwVersionInfoSize);

		//Use GetFileVersionInfo to copy the version info 
		//block into pVersion info.
		if (!GetFileVersionInfo(szLocation, 0, dwVersionInfoSize, pVersionInfo))
		{
			if (debug) {
				sprintf(szMessage, "Could not get file information for %s", szLocation);
				OutputDebugString(szMessage);
			}
			free(pVersionInfo);
			MSINeedsInstalling = true;
			return;
		}

		//Use VerQueryValue to parse the version information
		//data block and get a pointer to the VS_FIXEDFILEINFO
		//structure.
		VS_FIXEDFILEINFO* pFixedFileInfo;
		UINT nBytesReturned;
		if (!VerQueryValue(pVersionInfo, "\\", (void**)&pFixedFileInfo, &nBytesReturned))
		{
			if (debug) {
				sprintf(szMessage, "Could not get version information for %s", szLocation);
				OutputDebugString(szMessage);
			}
			free(pVersionInfo);
			MSINeedsInstalling = true;
			return;
		}
	         
		WORD major = HIWORD(pFixedFileInfo->dwFileVersionMS);
		WORD minor = LOWORD(pFixedFileInfo->dwFileVersionMS);
		if (major == 2)
			MSINeedsInstalling = false;
		//See the Help for VS_FIXEDFILEINFO structure... 
		//dwFileVersionMS and dwFileVersionLS
		//are probably the most commonly used members.
		//TCHAR szMessage[255];
		//_stprintf(szMessage, "Major version: %d  Minor version: %d", 
		//	HIWORD(pFixedFileInfo->dwFileVersionMS), 
		//	LOWORD(pFixedFileInfo->dwFileVersionMS));
	
//		MessageBox(NULL, "Found MSI", szMessage, MB_OK | MB_ICONINFORMATION);


		//Cleanup
		free(pVersionInfo);
	}
	else
	{
		if (debug)
			sprintf("Could not get file information for %s", szLocation);
		MSINeedsInstalling = true;
	}
	if (debug)
	{
		if (MSINeedsInstalling)
			OutputDebugString("MSI needs to be installed\n");
		else
			OutputDebugString("MSI does not need to be installed\n");
	}
	if (test)
		MSINeedsInstalling = true;
}


/**
Method to check to see if Microsoft's Data Access needs to be installed
*/
void checkMDAC()
{
	LPCTSTR location = g_settings.GetMDACPath();
	//First check to see if we have a path. If not, don't install
	if (location[0] == END_OF_STRING)
		return;
	// now we'll check the registry for this value
	//
	LONG lResult;
	HKEY hkey = NULL;
	
	lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, // handle to open key
							g_tszMDACRegKey,      // name of subkey to open
							NULL,
							KEY_READ,
							&hkey               // handle to open key
							);

	// we don't proceed unless the call above succeeds
	if ((ERROR_SUCCESS != lResult) || (ERROR_FILE_NOT_FOUND == lResult))
	{
		MDACNeedsInstalling = true;
		//throw HRESULT_FROM_WIN32(lResult);
		return;
	}

	TCHAR szVersion[256];
	if (ERROR_SUCCESS == lResult)
	{
		DWORD dwBufLen = LENGTH(szVersion);

		lResult = RegQueryValueEx( hkey,
								g_tszMDACRegKeyValue,
								NULL,
								NULL,
								(LPBYTE)szVersion,
								&dwBufLen);
	    
		// if we receive an error other than 0x2, throw
		if (ERROR_SUCCESS == lResult)
		{
			double registryVersion = atof(szVersion);
			double requiredVersion = atof(g_settings.GetMDACVersion());
			if (registryVersion < requiredVersion)
				MDACNeedsInstalling = true;
		}
		else if (ERROR_FILE_NOT_FOUND != lResult)
		{
			MDACNeedsInstalling = true;
		}

		RegCloseKey(hkey);
	}
	if (debug)
	{
		if (MDACNeedsInstalling)
			OutputDebugString("MDAC needs to be installed\n");
		else
			OutputDebugString("MDAC does not need to be installed\n");
	}
	if (test)
		MDACNeedsInstalling = true;
}

void checkDotNetServicePack()
{
	// check the registry for this value
	//
	LONG lResult;
	HKEY hkey = NULL;
	
	lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, // handle to open key
							g_tszFxServicePackRegKey,      // name of subkey to open
							NULL,
							KEY_READ,
							&hkey               // handle to open key
							);

	// we don't proceed unless the call above succeeds
	if ((ERROR_SUCCESS != lResult) || (ERROR_FILE_NOT_FOUND == lResult))
	{
		FxServicePackNeedsInstalling = true;
		//throw HRESULT_FROM_WIN32(lResult);
		return;
	}

	TCHAR szInstalled[10];
	if (ERROR_SUCCESS == lResult)
	{
		DWORD dwBufLen = LENGTH(szInstalled);

		lResult = RegQueryValueEx( hkey,
								g_tszFxServicePackRegKeyValue,
								NULL,
								NULL,
								(LPBYTE)szInstalled,
								&dwBufLen);
	    
		if (ERROR_SUCCESS == lResult)
		{
			//Success
		}
		// if we receive an error other than 0x2
		else if (ERROR_FILE_NOT_FOUND != lResult)
		{
			FxServicePackNeedsInstalling = true;
		}

		RegCloseKey(hkey);
	}
	if (debug)
	{
		if (FxServicePackNeedsInstalling)
			OutputDebugString("Fx Service Pack needs to be installed\n");
		else
			OutputDebugString("Fx Service Pack does not need to be installed\n");
	}
	if (test)
		FxServicePackNeedsInstalling = true;
}

void checkExtraProgram1()
{
	LPCTSTR location = g_settings.GetExtraProgramPath1();
	//First check to see if we have a path. If not, don't install
	if (location[0] == END_OF_STRING)
		return;
	ExtraProgramPath1NeedsInstalling = true;
}

/**
Method to check to see if Microsoft's SQL Desktop Engine needs to be installed
*/
void checkMSDE()
{
	LPCTSTR location = g_settings.GetMSDEPath();
	//First check to see if we have a path. If not, don't install
	if (location[0] == END_OF_STRING)
		return;
	// now we'll check the registry for this value
	//
	LONG lResult;
	HKEY hkey = NULL;
	
	lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, // handle to open key
							g_tszMSDERegKey,      // name of subkey to open
							NULL,
							KEY_READ,
							&hkey               // handle to open key
							);

	// If the key doesn't exist then it hasn't been installed
	if ((ERROR_SUCCESS != lResult) || (ERROR_FILE_NOT_FOUND == lResult))
	{
		MSDENeedsInstalling = true;
		return;
	}

	TCHAR szVersion[256];
	if (ERROR_SUCCESS == lResult)
	{
		DWORD dwBufLen = LENGTH(szVersion);

		lResult = RegQueryValueEx( hkey,
								g_tszMSDERegKeyValue,
								NULL,
								NULL,
								(LPBYTE)szVersion,
								&dwBufLen);
	    
		// if we receive an error other than 0x2, throw
		if (ERROR_SUCCESS == lResult)
		{
			checkMSDEService(); // Check to see if service exists
		}
		else if (ERROR_FILE_NOT_FOUND == lResult)
		{
			MSDENeedsInstalling = true;
		}

		RegCloseKey(hkey);
	}

	if (debug)
	{
		if (MSDENeedsInstalling)
			OutputDebugString("MSDE needs to be installed\n");
		else
			OutputDebugString("MSDE does not need to be installed\n");
	}
	if (test)
		MSDENeedsInstalling = true;
}

/*
Check to see if the MSDE Service is running
*/
BOOL checkMSDEService()
{
	if ( IsServiceAvailable( "MSSQLSERVER" ) )
	{
		MSDENeedsInstalling = false;
		return true;
	}
	else
	{
		MSDENeedsInstalling = true;
		return false;
	}
}

// Is the service with the given name available
BOOL IsServiceAvailable( LPCTSTR service_name )
{
	SC_HANDLE hHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (hHandle == NULL) 
		return FALSE;
	SC_HANDLE hService = OpenService( hHandle, service_name, SERVICE_ALL_ACCESS );
	if (!hService && GetLastError() != ERROR_ACCESS_DENIED ) 
		return FALSE;

	CloseServiceHandle(hHandle);
	return TRUE;
}

// Set the text for the bill board
void setBillBoardText(LPTSTR text) 
{
	SetDlgItemText(billBoard, IDC_TEXT, text);
}

INT_PTR CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
// the dialog procedure
{
	switch(msg)
	{
		case WM_INITDIALOG: // our dialog is being shown
			{
				HWND desktop = GetDesktopWindow();
				RECT screenRect, dialogRect;
				GetClientRect(desktop, &screenRect);
				GetClientRect(hwnd, &dialogRect);
				SetWindowPos(hwnd, HWND_TOP, (screenRect.right-screenRect.left)/2 - (dialogRect.right - dialogRect.left)/2,
					(screenRect.bottom-screenRect.top)/2 - (dialogRect.bottom - dialogRect.top)/2,
					 dialogRect.right - dialogRect.left, dialogRect.bottom - dialogRect.top, SWP_NOSIZE);
				HWND control = GetDlgItem(hwnd, IDC_IE);
				if ((IENeedsInstalling == true) || test)
				{
					EnableWindow(control, true);
					CheckDlgButton(hwnd, IDC_IE, BST_CHECKED);
				}
				else 
				{
					EnableWindow(control, false);
				}
//				control = GetDlgItem(hwnd, IDC_MSI);
//				if (!test)
//					EnableWindow(control, false);
//				if (MSINeedsInstalling)
//					CheckDlgButton(hwnd, IDC_MSI, BST_CHECKED);
				control = GetDlgItem(hwnd, IDC_DOTNET);
				if ((DotNetINeedsInstalling) || test)
				{
					EnableWindow(control, true);
					CheckDlgButton(hwnd, IDC_DOTNET, BST_CHECKED);
				}
				else 
				{
					EnableWindow(control, false);
				}
				control = GetDlgItem(hwnd, IDC_MDAC);
				if ((MDACNeedsInstalling) || test)
				{
					EnableWindow(control, true);
					CheckDlgButton(hwnd, IDC_MDAC, BST_CHECKED);
				}
				else // disable if it doesn't need to be installed
				{
					EnableWindow(control, false);
				}
				control = GetDlgItem(hwnd, IDC_MSDE);
				if ((MSDENeedsInstalling) || test)
				{
					EnableWindow(control, true);
					CheckDlgButton(hwnd, IDC_MSDE, BST_CHECKED);
				}
				else // disable if it doesn't need to be installed
					EnableWindow(control, false);
				BringWindowToTop(hwnd); // Bring it to the front
			}
			break;

		case WM_COMMAND: // we got a message from a control/menu
			// in this case, a button
			switch(LOWORD(wParam))
			{
				case IDOK: // the INSTALL button
					EndDialog(hwnd, TRUE); 
					break; 

				case IDCANCEL:     // user pressed either exit, the X on the top
					// right, or used ALT+F4
					EndDialog(hwnd, FALSE);
					break;

				case IDC_IE:     // user unchecked IE (only on test is this available)
					{
						HWND control = GetDlgItem(hwnd, IDC_IE);
						if (IsDlgButtonChecked(hwnd, IDC_IE) == BST_CHECKED)
							IENeedsInstalling = true;
						else
							IENeedsInstalling = false;
						break;
					}

/*				case IDC_MSI:     // user unchecked MSI
					{
						HWND control = GetDlgItem(hwnd, IDC_MSI);
						if (IsDlgButtonChecked(hwnd, IDC_MSI) == BST_CHECKED)
							MSINeedsInstalling = true;
						else
							MSINeedsInstalling = false;
						break;
					}
*/
				case IDC_MDAC:     // user unchecked MDAC
					{
						HWND control = GetDlgItem(hwnd, IDC_MDAC);
						if (IsDlgButtonChecked(hwnd, IDC_MDAC) == BST_CHECKED)
							MDACNeedsInstalling = true;
						else
							MDACNeedsInstalling = false;
						break;
					}

				case IDC_MSDE:     // user unchecked MSDE
					{
						HWND control = GetDlgItem(hwnd, IDC_MSDE);
						if (IsDlgButtonChecked(hwnd, IDC_MSDE) == BST_CHECKED)
							MSDENeedsInstalling = true;
						else
							MSDENeedsInstalling = false;
						break;
					}

				case IDC_DOTNET:     // user unchecked DOTNET
					{
						HWND control = GetDlgItem(hwnd, IDC_DOTNET);						
						if (IsDlgButtonChecked(hwnd, IDC_DOTNET) == BST_CHECKED)
							DotNetINeedsInstalling = true;
						else
							DotNetINeedsInstalling = false;
						break;
					}
					break; 


				}
			break;

		case WM_DESTROY: // dialog is off the screen by now
			break;

		default: // all the messages we don't handle
		// are handled by Windows

		return FALSE; // this means we haven't processed it
	}
	return TRUE; // this one means we have processed the message
}

void InsertRegistryRun()
{
	try
	{
		HKEY l_HKey;
		LONG l_result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
					c_Reg_Run,
					0,
					KEY_WRITE,
					&l_HKey);
		if (l_result != ERROR_SUCCESS)
			return;

		TCHAR l_ExeName[2000];
		
		GetModuleFileName(NULL,(LPTSTR)l_ExeName,LENGTH(l_ExeName));
		RegSetValueEx(l_HKey, c_dotNetInstaller,0,REG_SZ,(LPBYTE)(LPCTSTR)l_ExeName, (DWORD)(LENGTH(l_ExeName)+1) );

		RegCloseKey(l_HKey);
	}
	catch(...)
	{
		_ASSERT(false);
	}
};

void RemoveRegistryRun()
{
	try
	{
		HKEY l_HKey;
		LONG l_result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
					c_Reg_Run,
					0,
					KEY_WRITE,
					&l_HKey);
		if (l_result != ERROR_SUCCESS)
			return;

		RegDeleteValue(l_HKey, c_dotNetInstaller);

		RegCloseKey(l_HKey);
	}
	catch(...)
	{
		_ASSERT(false);
	}
};

BOOL SetWorkingDir()
 {
 // Desc: Retrieves the directory of the application.
 //  Pre: None.
 // Post: The return value is the directory of the application ending in
 //'\'.

	TCHAR app_path[2000];
	GetModuleFileName(NULL,(LPTSTR)app_path,LENGTH(app_path));
	LONG len = LENGTH( app_path );
	while ((len > 0) && ('\\' != app_path[ len - 1 ]))
	--len;
	app_path[ len ] = '\0';

	return SetCurrentDirectory((LPCTSTR)app_path);
 }


DWORD runExe(LPCTSTR pszCmd)
{
    // show 'setup is working...' msg
//    ShowBillboard(&g_dwThread, &g_hThread);

    // execute dotnetfx.exe setup
    DWORD dwResult = ExecCmd(pszCmd);
    
    // take down billboard
//    TeardownBillboard(g_dwThread, g_hThread);
	return dwResult;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Kevin Moore
Web Developer
United States United States
No Biography provided

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141223.1 | Last Updated 24 Nov 2005
Article Copyright 2003 by Kevin Moore
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid