//+------------------------------------------------------------------
//																	
//  Project:	Windows NT4 DS Client Setup Wizard				
//
//  Purpose:	Installs the Windows NT4 DS Client Files			
//
//  File:		dscsetup.cpp
//
//  History:	March 1998	Zeyong Xu	Created
//            Jan   2000  Jeff Jones (JeffJon) Modified
//                        - changed to be an NT setup
//																	
//------------------------------------------------------------------


#include <windows.h>
#include <prsht.h>
#include <setupapi.h>
#include <tchar.h>
#include <stdlib.h>
#include "resource.h"
#include "dscsetup.h"
#include "wizard.h"

#include "doinst.h"


SInstallVariables	g_sInstVar;


// DllMain Entry 
BOOL APIENTRY DllMain( HINSTANCE hInstance, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
    switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH:
		case DLL_THREAD_ATTACH:
		case DLL_THREAD_DETACH:
		case DLL_PROCESS_DETACH:
			break;
    }
    return TRUE;
}


// This is an exported function.
DWORD WINAPI DoDscSetup(LPCSTR lpCmdLine)
{
	// initialize the variables of installation
	InitVariables();

	ParseCmdline(const_cast<PSTR>(lpCmdLine));

  //
  // Go through setup if we are installing with anything but
  // the /a flag
  //
  if (g_sInstVar.m_bSysDlls || g_sInstVar.m_bWabInst)
  {
	  // create objects
	  if(!CreateObjects())
          return SETUP_ERROR;

	  // Launch setup wizard
	  if(!DSCSetupWizard()) 
	  {
		  TCHAR		szMessage[MAX_MESSAGE + 1]; 
		  TCHAR		szTitle[MAX_TITLE + 1]; 

		  LoadString(g_sInstVar.m_hInstance, 
                     IDS_ERROR_WIZARD,
                     szMessage, 
                     MAX_MESSAGE);
		  LoadString(g_sInstVar.m_hInstance, 
                     IDS_ERROR_TITLE, 
                     szTitle, 
                     MAX_TITLE);

		  // display a error message - Failure to load Setup Wizard
		  MessageBox(NULL,	
					  szMessage,	// address of text in message box
					  szTitle,	// address of title of message box  
					  MB_OK | MB_TOPMOST | MB_ICONERROR);  // style of message box

		  g_sInstVar.m_nSetupResult = SETUP_ERROR;
	  }

	  // destroy objects
	  DestroyObjects();

	  if(g_sInstVar.m_nSetupResult == SETUP_SUCCESS &&
             !g_sInstVar.m_bQuietMode
#ifdef MERRILL_LYNCH
             && !g_sInstVar.m_bNoReboot
#endif
             )
	  {
		  // prompt reboot
		  SetupPromptReboot(NULL,		// optional, handle to a file queue
						  NULL,          // parent window of this dialog box
						  FALSE);        // optional, do not prompt user);
	  }
     else if(g_sInstVar.m_nSetupResult == SETUP_SUCCESS &&
             g_sInstVar.m_bQuietMode 
#ifdef MERRILL_LYNCH
             && !g_sInstVar.m_bNoReboot
#endif
             )
     {
         HANDLE htoken = INVALID_HANDLE_VALUE;

         do
         {
            // twiddle our process privileges to enable SE_SHUTDOWN_NAME
            HRESULT hr = OpenProcessToken(GetCurrentProcess(),
                                          TOKEN_ADJUST_PRIVILEGES,
                                          &htoken);
            if (FAILED(hr))
            {
               break;
            }

            LUID luid;
            memset(&luid, 0, sizeof(luid));
            hr = LookupPrivilegeValue(0, SE_SHUTDOWN_NAME, &luid);
            if (FAILED(hr))
            {
               break;
            }

            TOKEN_PRIVILEGES privs;
            memset(&privs, 0, sizeof(privs));
            privs.PrivilegeCount = 1;
            privs.Privileges[0].Luid = luid;
            privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

            hr = AdjustTokenPrivileges(htoken, 0, &privs, 0, 0, 0);
            if (FAILED(hr))
            {
               break;
            }

            hr = ExitWindowsEx(EWX_REBOOT, 0);
            if (FAILED(hr))
            {
               break;
            }
         }
         while (0);

         if (htoken != INVALID_HANDLE_VALUE)
         {
            CloseHandle(htoken);
         }

     }
  }
  else
  {
    //
    // Setup was run with the /a flag.  This means we
    // don't want to show the UI and let the adsix86.inf
    // handle the install for us
    //
    if (!LaunchProcess(STR_INSTALL_ADSIWREMOVE))
    {
      g_sInstVar.m_nSetupResult = SETUP_ERROR;
    }
  }
	return g_sInstVar.m_nSetupResult;
}


VOID ParseCmdline(LPSTR lpCmdLine)
{
  PCTSTR ptszTok = _tcstok(lpCmdLine, _T(" "));
  do
  {
    if (ptszTok != NULL)
    {
      if (_tcsicmp(ptszTok, _T("/q")) == 0)
      {
        g_sInstVar.m_bQuietMode = TRUE;
      }

      if (_tcsicmp(ptszTok, _T("/a")) == 0)
      {
        g_sInstVar.m_bWabInst = FALSE;
        g_sInstVar.m_bSysDlls = FALSE;
      }

      if (_tcsicmp(ptszTok, _T("/d")) == 0)
      {
        g_sInstVar.m_bWabInst = FALSE;
      }
#ifdef MERRILL_LYNCH
      if (_tcsicmp(ptszTok, _T("/n")) == 0)
      {
        g_sInstVar.m_bNoReboot = TRUE;
      }
#endif
    }
    ptszTok = _tcstok(NULL, _T(" "));
  } while (ptszTok != NULL);
}


// initialize the variables of installation
VOID InitVariables()
{
	g_sInstVar.m_hInstance = GetModuleHandle(STR_DLL_NAME);
  g_sInstVar.m_hInstallThread = NULL;
	g_sInstVar.m_uTimerID = 0;
  g_sInstVar.m_hBigBoldFont = NULL;
	g_sInstVar.m_hProgress = NULL;
	g_sInstVar.m_hFileNameItem = NULL;

  g_sInstVar.m_bDCOMInstalled = FALSE;

	g_sInstVar.m_bQuietMode = FALSE;
  g_sInstVar.m_bWabInst = TRUE;
  g_sInstVar.m_bSysDlls = TRUE;
#ifdef MERRILL_LYNCH
  g_sInstVar.m_bNoReboot = FALSE;
#endif
	g_sInstVar.m_nSetupResult = SETUP_SUCCESS;

  // get source path
  GetModuleFileName(g_sInstVar.m_hInstance,
                    g_sInstVar.m_szSourcePath, 
                    MAX_PATH);
  *(_tcsrchr(g_sInstVar.m_szSourcePath, CHAR_BACKSLASH) + 1) = TEXT('\0');       // Strip setup.exe off path
}

// start setup wizard
BOOL DSCSetupWizard()
{
	PROPSHEETHEADER psh;
	PROPSHEETPAGE	psPage[SIZE_WIZARD_PAGE];
	int  i = 0;

	//
	// Setup the Welcome page
	//
    i=0;
	ZeroMemory(&psPage[i],sizeof(PROPSHEETPAGE));
	psPage[i].dwSize = sizeof(PROPSHEETPAGE);
	psPage[i].dwFlags = PSP_USETITLE | PSP_HIDEHEADER;
	psPage[i].hInstance = g_sInstVar.m_hInstance;
	psPage[i].pszTemplate = MAKEINTRESOURCE(IDD_WELCOME);
	psPage[i].pfnDlgProc = (DLGPROC) WelcomeDialogProc;
	psPage[i].lParam = (LPARAM) 0;
	psPage[i].pszTitle = MAKEINTRESOURCE(IDS_WIZARD_TITLE);

/* ntbug#337931: remove license page
    //
	// Setup the License Page
	//
    i++;
	ZeroMemory(&psPage[i],sizeof(PROPSHEETPAGE));
	psPage[i].dwSize = sizeof(PROPSHEETPAGE);
	psPage[i].dwFlags = PSP_USETITLE | 
                        PSP_USEHEADERTITLE | 
                        PSP_USEHEADERSUBTITLE;
	psPage[i].hInstance = g_sInstVar.m_hInstance;
	psPage[i].pszTemplate = MAKEINTRESOURCE(IDD_LICENSE);
	psPage[i].pfnDlgProc = (DLGPROC) LicenseDialogProc;
	psPage[i].lParam = (LPARAM) 0;
	psPage[i].pszTitle = MAKEINTRESOURCE(IDS_WIZARD_TITLE);
	psPage[i].pszHeaderTitle = MAKEINTRESOURCE(IDS_HEADERTITLE_LICENSE);
	psPage[i].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_HEADERSUBTITLE_LICENSE);
*/
	//
	// Setup the Select Page
	//
    i++;
	ZeroMemory(&psPage[i],sizeof(PROPSHEETPAGE));
	psPage[i].dwSize = sizeof(PROPSHEETPAGE);
	psPage[i].dwFlags = PSP_USETITLE | 
                        PSP_USEHEADERTITLE |
                        PSP_USEHEADERSUBTITLE;
	psPage[i].hInstance = g_sInstVar.m_hInstance;
	psPage[i].pszTemplate = MAKEINTRESOURCE(IDD_CONFIRM);
	psPage[i].pfnDlgProc = (DLGPROC) ConfirmDialogProc;
	psPage[i].lParam = (LPARAM) 0;
	psPage[i].pszTitle = MAKEINTRESOURCE(IDS_WIZARD_TITLE);
	psPage[i].pszHeaderTitle = MAKEINTRESOURCE(IDS_HEADERTITLE_CONFIRM);
	psPage[i].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_HEADERSUBTITLE_CONFIRM);

	//
	// Setup the Confirm Page
	//
    i++;
	ZeroMemory(&psPage[i],sizeof(PROPSHEETPAGE));
	psPage[i].dwSize = sizeof(PROPSHEETPAGE);
	psPage[i].dwFlags = PSP_USETITLE | 
                        PSP_USEHEADERTITLE | 
                        PSP_USEHEADERSUBTITLE;
	psPage[i].hInstance = g_sInstVar.m_hInstance;
	psPage[i].pszTemplate = MAKEINTRESOURCE(IDD_INSTALL);
	psPage[i].pfnDlgProc = (DLGPROC) InstallDialogProc;
	psPage[i].lParam = (LPARAM) 0;
	psPage[i].pszTitle = MAKEINTRESOURCE(IDS_WIZARD_TITLE);
	psPage[i].pszHeaderTitle = MAKEINTRESOURCE(IDS_HEADERTITLE_INSTALL);
	psPage[i].pszHeaderSubTitle = MAKEINTRESOURCE(IDS_HEADERSUBTITLE_INSTALL);

	//
	// Setup the Completion page
	//
    i++;
	ZeroMemory(&psPage[i],sizeof(PROPSHEETPAGE));
	psPage[i].dwSize = sizeof(PROPSHEETPAGE);
	psPage[i].dwFlags = PSP_USETITLE | PSP_HIDEHEADER;
	psPage[i].hInstance = g_sInstVar.m_hInstance;
	psPage[i].pszTemplate = MAKEINTRESOURCE(IDD_COMPLETION);
	psPage[i].pfnDlgProc = (DLGPROC) CompletionDialogProc;
	psPage[i].lParam = (LPARAM) 0;
	psPage[i].pszTitle = MAKEINTRESOURCE(IDS_WIZARD_TITLE);

	//
	// Setup the wizard
	//
	ZeroMemory(&psh,sizeof(PROPSHEETHEADER));
	psh.dwSize = sizeof(PROPSHEETHEADER);
	// Windows 98 with 16 color display mode crashes when PSH_STRETCHWATERMARK flag is on.
	psh.dwFlags = PSH_USEICONID | 
                  PSH_PROPSHEETPAGE | 
                  PSH_WIZARD97 |
                  PSH_WATERMARK |
                  PSH_HEADER; // | PSH_STRETCHWATERMARK;
	psh.pszIcon = MAKEINTRESOURCE(IDI_ICON_APP);
	psh.hInstance = g_sInstVar.m_hInstance;
	psh.pszCaption = MAKEINTRESOURCE(IDS_WIZARD_TITLE);;
	psh.nStartPage = 0;
	psh.nPages = SIZE_WIZARD_PAGE;
	psh.ppsp = (LPCPROPSHEETPAGE) &psPage;

	//
	// Run the wizard
	//
	if(g_sInstVar.m_bQuietMode)
    {
        if(!CheckDiskSpace())
            return FALSE;

        psh.nStartPage = 2;
    }
	else
		psh.nStartPage = 0;

	if( PropertySheet(&psh) < 0 )	// failure to load wizard
	{
		return FALSE;
	}

	//
	// Because SetWindowLongPtr(hWnd, DWL_MSGRESULT, IDD_COMPLETION) 
    // doesn't work on Win95 (when users click Cancel, the wizard can't
    // be routed to the Completion page), I added the following code to
    // open the Completion page
	//
	if(!g_sInstVar.m_bQuietMode)
	{
		psh.nStartPage = 3;
		if( PropertySheet(&psh) < 0 )	// failure to load wizard
		{
			return FALSE;
		}
	}
	
	return TRUE;
}


// check for DCOM installed
void CheckDCOMInstalled()
{
	HKEY		hSubKey;

	// check if IE 4.0 has been installed
	if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, 
									  STR_DCOM_REGKEY, 
									  0, 
									  KEY_READ, 
									  &hSubKey)	)
	{
        g_sInstVar.m_bDCOMInstalled = TRUE;
		RegCloseKey(hSubKey);
	}
}

//  gets Disk Free space
DWORD64 SetupGetDiskFreeSpace()
{
    DWORD		dwSectorsPerCluster;
    DWORD		dwBytesPerSector;
    DWORD		dwNumberOfFreeClusters;
    DWORD		dwTotalNumberOfClusters;
    DWORD64  	d64FreeSpace = 0;
    TCHAR		szPathName[MAX_PATH + 1];	        // address of root path 

	if(GetSystemDirectory(szPathName,  // address of buffer for system directory
						  MAX_PATH))       // size of directory buffer);
	{
		if ( szPathName[1] == TEXT(':'))
		{
			// this is a drive letter
			// assume it is of for d:backslash
			szPathName[3] = TEXT('\0');		

			//get free space, GetDiskFreeSpaceEx() don't support in older Win95
			if (GetDiskFreeSpace(szPathName,	        // address of root path 
								 &dwSectorsPerCluster,	    // address of sectors per cluster 
								 &dwBytesPerSector,	        // address of bytes per sector 
								 &dwNumberOfFreeClusters,	// address of number of free clusters  
								 &dwTotalNumberOfClusters)) // address of total number of clusters  
			{
				// calc total  size
				d64FreeSpace = DWORD64(dwSectorsPerCluster)
							  * dwBytesPerSector
							  * dwNumberOfFreeClusters;
			}
		}
	}

	return d64FreeSpace;
}

// check if DSClient has been installed
BOOL CheckDSClientInstalled()
{
	HKEY	hSubKey;
	BOOL	bResult = FALSE;

	// open reg key of DS Client
	if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
									  STR_DSCLIENT_REGKEY,
									  0, 
									  KEY_ALL_ACCESS, 
									  &hSubKey)	) 
	{
		bResult = TRUE;		
		RegCloseKey(hSubKey);
	}

	return bResult;
}

/* ntbug#337931: remove license page
//  load "License Agreement" text from license file 
BOOL LoadLicenseFile(HWND hDlg)
{
	BOOL    bReturn = FALSE;
	TCHAR	szTitle[MAX_TITLE + 1];
	TCHAR	szTempBuffer[MAX_MESSAGE + 1];
	TCHAR	szLicenseFile[MAX_PATH + 1];
	TCHAR	szReturnTextBuffer[MAX_MESSAGE + 1]; 
    LPTSTR	lpszLicenseText = NULL;
    HANDLE	hFile;
    DWORD	dwNumberOfBytesRead, dwFileSize;

    //
    // Determine where we are installing from
    // and specific the license file there
    //
	lstrcpy(szLicenseFile, g_sInstVar.m_szSourcePath);
	lstrcat(szLicenseFile, STR_LICENSEFILE);	
	
    // Open License file
    hFile = CreateFile(szLicenseFile,       // pointer to name of the file 
                       GENERIC_READ,          // access (read-write) mode 
                       FILE_SHARE_READ,       // share mode 
                       NULL,                  // pointer to security descriptor 
                       OPEN_EXISTING,         // how to create 
                       FILE_ATTRIBUTE_NORMAL, // file attributes 
                       NULL);                 // handle to file with attributes to copy  

    if(INVALID_HANDLE_VALUE != hFile)
    {                
	
		// Read License file into string
		// setup memory, get file size in bytes
		dwFileSize = GetFileSize (hFile, NULL) ;

		if (dwFileSize != 0xFFFFFFFF) 
		{ 		
            // this program is for Win98/95, it will work in MBCS not UNICODE
            // this code is for ANSI US version, license.txt file uses the single byte character set(ANSI)
            // if doing locolization, license.txt file should use the double byte character set(DBCS/MBCS)
			lpszLicenseText = (LPTSTR) calloc (dwFileSize + sizeof(TCHAR), 
                                               sizeof(BYTE));
		}

		if(lpszLicenseText)
		{
			//read file
			if (ReadFile(hFile,    	// handle of file to read 
						  lpszLicenseText,    // address of buffer that receives data  
						  dwFileSize,    	// number of bytes to read 
						  &dwNumberOfBytesRead,    // address of number of bytes read 
						  NULL))                // address of structure for data 
			{
				// display license on dialog
				SetDlgItemText(hDlg, IDC_LICENSE_TEXT, lpszLicenseText);

				bReturn = TRUE;
			}

			// so free the memory
			free(lpszLicenseText);
		}

		//close file handle
		CloseHandle(hFile);
 	}
	
	if(!bReturn)
	{
		// load string
		LoadString(g_sInstVar.m_hInstance, 
                   IDS_ERROR_TITLE,
                   szTitle, 
                   MAX_TITLE);
		LoadString(g_sInstVar.m_hInstance, 
                   IDS_ERROR_LICENSEFILE, 
                   szTempBuffer, 
                   MAX_MESSAGE);
		wsprintf(szReturnTextBuffer, 
                 TEXT("%s %s"), 
                 szTempBuffer,
                 szLicenseFile);

		MessageBox(hDlg, 
			szReturnTextBuffer,
			szTitle, 
			MB_OK | MB_TOPMOST | MB_ICONERROR);
	}
      
    return bReturn;
}
*/

// check disk space
BOOL CheckDiskSpace()
{
	BOOL  bResult = TRUE;
	TCHAR  szString[MAX_MESSAGE + MAX_TITLE + 1];
	TCHAR  szTitle[MAX_TITLE + 1];
	TCHAR  szMessage[MAX_MESSAGE + 1];

	if(SIZE_TOTAL*MB_TO_BYTE > SetupGetDiskFreeSpace())
	{
		// load string
		LoadString(g_sInstVar.m_hInstance, 
                   IDS_ERROR_NODISKSPACE, 
                   szMessage, 
                   MAX_MESSAGE);
		LoadString(g_sInstVar.m_hInstance, 
                   IDS_ERROR_TITLE, 
                   szTitle, 
                   MAX_TITLE);
		wsprintf(szString,
                 TEXT("%s %d MB."), 
                 szMessage, 
                 SIZE_TOTAL); 
            
		MessageBox(NULL,
				szString,
				szTitle, 
				MB_OK | MB_TOPMOST | MB_ICONERROR);

		bResult = FALSE;
	}

	return bResult;
}

// create objects
BOOL CreateObjects()
{
    try
    {
        // initialize the synchronizing object
        InitializeCriticalSection(&g_sInstVar.m_oCriticalSection);
    }
    catch(...)
    {
        return FALSE;
    }

    // create a 12 pt big font
    CreateBigFont();

    return TRUE;
}

// destroy objects
VOID DestroyObjects()
{
    // wait to finish the runing setup process
    if(g_sInstVar.m_hInstallThread)
    {
        // wait the installation thread to finish
	    WaitForSingleObject(g_sInstVar.m_hInstallThread,INFINITE);
   		CloseHandle(g_sInstVar.m_hInstallThread);
    }

   	// delete the synchronizing object
	DeleteCriticalSection(&g_sInstVar.m_oCriticalSection);

    //Frees up the space used by loading the fonts
    if( g_sInstVar.m_hBigBoldFont ) 
	{
        DeleteObject( g_sInstVar.m_hBigBoldFont );
    }

}

//create a big font for dialog title
VOID CreateBigFont()
{
    NONCLIENTMETRICS ncm;
    LOGFONT BigBoldLogFont;
    HDC hdc;

    // Create the fonts we need based on the dialog font
	ZeroMemory(&ncm,sizeof(NONCLIENTMETRICS));
    ncm.cbSize = sizeof(NONCLIENTMETRICS);
    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
	BigBoldLogFont = ncm.lfMessageFont;
    BigBoldLogFont.lfWeight = FW_BOLD;

	hdc = GetDC(NULL);
    if( hdc )
    {
        BigBoldLogFont.lfHeight = 0 - 
                                  (GetDeviceCaps(hdc,LOGPIXELSY) * 
                                   SIZE_TITLE_FONT / 
                                   72);

        g_sInstVar.m_hBigBoldFont = CreateFontIndirect(&BigBoldLogFont);

        ReleaseDC(NULL,hdc);
    }
}