/*
 #########################################################################
 ## Installation program for Windows 95/98/NT/2000 driver               ##
 ##                    Main module ( linked with DIALOG.C )             ##
 ##                                             (C) Aktiv Co. 1997-2001 ##
 #########################################################################
*/
#include <windows.h>
#include <stdio.h>

#include "instdrv.h"
#include "instdrvs.h"
#include "instdrvf.h"
#include "inststr.h"


 static char szText[0x120];

 TDriverState DrvState;    // Current driver state

 BOOL bHide;               // Quiet mode flag: if TRUE - no messages will be dispayed
 BOOL bAlwaysAskForReboot; // Always prompt before reboot the system. /Q option is omitted.
 BOOL bSkipReboot;         // Do not reboot the system;
 BOOL bInfo;               // Help mode flag: display help screen
 BOOL bPrintLog;           // If TRUE - every action will be logged to file INSTDRV.LOG
 BOOL bWinNT2000;          // System type flag: TRUE if NT/2000
 BOOL bMultiProc;		   // System type flag: TRUE if Multiprocessor mode

 BOOL bUSBPresent;	   	   // USB availability flag

 int  bRus;                // TRUE - russian. This value is 0 or 1000
 HINSTANCE hMainInstance;  // Application instance for resource loading
 int  CurDrvVer;           // Version of currently installed driver.
                           // Dispayed in the left lower corner of dialog

 char*               RS                    ( int  );
 int                 MakeOperation         ( int  );
 void                TryToExitWindows      ( void );
 BOOL 				 IsXDigitStr		   ( char *szStr, BYTE byLen );
 extern BOOL _export CALLBACK MsgDlgProc   ( HWND, UINT, WPARAM, LPARAM );
 extern int          CheckDriver           ( void );

// This function is necessary then INSTAPI.DLL is not used...
// Please do not try to define INSTALL_WITHOUT_DLL
#ifdef INSTALL_WITHOUT_DLL
 extern int          InitLibrary           ( HINSTANCE );
#endif


/*-----------------------------------------------------------------*/

BOOL IsMultiProc(void)
{
	SYSTEM_INFO SI;

    GetSystemInfo(&SI);
    if(SI.dwNumberOfProcessors > 1L)
    	return TRUE;
	else
    	return FALSE;
}

/*-----------------------------------------------------------------*/

BOOL IsXDigitStr(char *szStr, BYTE byLen)
{
	int i;

	for(i=0; i < byLen; i++){
    	if(szStr[i] == 0x0)
    		break;
		if(!isxdigit(szStr[i]))
    		return FALSE;
 	}
	return TRUE;
}

/*-----------------------------------------------------------------*/

// Returns string from resource in current language
char * RS(int ID)
{
 static char szResourceBuffer[255];

 if (!LoadString( hMainInstance,ID + bRus,szResourceBuffer,255))
 {
    sprintf (szText,"Unable to load resource string #%d (Error %ld)",ID,GetLastError());
    MessageBox(NULL,szText,"Fatal error",MB_);
    strcpy(szResourceBuffer,"---------\0");
 }
 return szResourceBuffer;
}

//-------------------------------------------------------------------------
// This routine performs install/unistall operations and shows status message
//-------------------------------------------------------------------------
int  MakeOperation( int  nCommand )
{
 int nRet;
 HCURSOR hCur;

 hCur = SetCursor(LoadCursor(NULL,IDC_WAIT));

 // if Uninstall ==> GD_RemoveDriver()
 // In all other cases GD_ReInstall()
 if( nCommand & COMMAND_UNINST )  // Uninstall driver
    nRet = GD_RemoveDriver( TRUE );
 else                             // Install or reinstall driver
    nRet =  GD_ReInstallDriver();

 // RebootNeeded is not error.
 if(nRet & ge_REBOOT_NEEDED)
// if ( nRet == ge_REBOOT_NEEDED )
 {
     DrvState.RebootNeeded = 1;
//     nRet = ge_NO_ERROR;
     nRet &= ~ge_REBOOT_NEEDED;
 }

 // Build and display status message

 if ( nRet == ge_NO_ERROR )
 {   if ( bWinNT2000 )
         sprintf (szText,RS(S_OKOK),"NT/2000/XP");
     else
         sprintf (szText,RS(S_OKOK),"95/98/Me");
     if ( nCommand & COMMAND_UNINST )
     {
       if ( bRus )  strcat (szText,"удален");
       else         strcat (szText,"uninstalled");
     }
     else
     {
       if ( bRus )  strcat  (szText,"установлен");
       else         strcat  (szText,"installed");
     }
 }
 else
 {
    if ( nCommand & COMMAND_UNINST)
    {
        if ( bRus )  sprintf  (szText,RS(S_FAIL),"удаления");
        else         sprintf  (szText,RS(S_FAIL),"uninstallation");
    }
    else
    {
      if ( bRus ) sprintf  (szText,RS(S_FAIL),"установки");
      else        sprintf  (szText,RS(S_FAIL),"installation");
    }
  }
 if  (!bHide && (nRet != ge_SERVICE_MARKED_FOR_DELETE))
    MessageBox( NULL, szText, RS(S_TITLE), MB_ | MB_ICONQUESTION );

 SetCursor(hCur);

 if ( DrvState.RebootNeeded )
     TryToExitWindows();
 return nRet;

}
//*********************************************************************************
//  This routine prompts user for reboot and reboots the system if [YES] button pressed.
//
void TryToExitWindows()
{
 DWORD				dwProcessID;
 HANDLE				hProcess, hToken;
 LUID 				Luid;
 TOKEN_PRIVILEGES 	TP;


 if ( bSkipReboot )
    return;
 sprintf(szText,RS(S_REBOOT));

 if (((!bHide)||(bAlwaysAskForReboot))&&
     (MessageBox (NULL,szText,RS(S_TITLE),MB_YESNO+MB_TASKMODAL)==IDNO))
     {
        GD_PrintLog ("Rebooting is cancelled by the user.");
        return;
     }
 GD_PrintLog ("-- Restarting Windows....");

 if(!bWinNT2000)
 	ExitWindowsEx (EWX_REBOOT, 0);
 else{
	dwProcessID = GetCurrentProcessId();
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);
    if(hProcess != NULL){
    	if(OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hToken)){
			if(LookupPrivilegeValue("", "SeShutdownPrivilege", &Luid)){
            	TP.PrivilegeCount = 1;
                TP.Privileges[0].Luid = Luid;
                TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
				if(AdjustTokenPrivileges(hToken, FALSE, &TP, 0, NULL, 0))
					ExitWindowsEx(EWX_REBOOT, 0);
            }
        }
    }
 }
 exit(4);

}
/*
*********************************************************************************
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
   ##   ##   ####  ######  ##   ##   | | | | | | | | | | | | | | | | | | | | | |
|  ### ###  ##  ##   ##    ###  ##  | | | | | | | | | | | | | | | | | | | | | |
   #######  ######   ##    #### ##   | | | | | | | | | | | | | | | | | | | | | |
|  ## # ##  ##  ##   ##    ## ####  | | | | | | | | | | | | | | | | | | | | | |
   ##   ##  ##  ## ######| ##   ##   | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
*********************************************************************************
*/

int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpszCmdLine, int nCmdShow )
{

 int   nCommand = 0;
 int   nRet;
 DWORD dwConfigFlags;

 hMainInstance = hInstance;
 strupr( lpszCmdLine );

 // This call is necessary then INSTAPI.DLL is not used...
 // Please do not try to define INSTALL_WITHOUT_DLL
#ifdef INSTALL_WITHOUT_DLL
 if (InitLibrary(hInstance)!=ge_NO_ERROR)
    return 6;
#endif

//------------------------------------------------------------------------

 GD_PrintLog ("-- Starting INSTDRV....");

 // Get versions of driver and system...
 GD_GetVersions(&bWinNT2000, &(BOOL)bRus, &CurDrvVer);
 // ...and detect USB...
 GD_GetUSBPresence(&bUSBPresent);
 // ...and get multiprocessors mode
 bMultiProc = IsMultiProc();
 // Change bRus to use it in resource strings loading procedure.
 bRus *= 1000;


 {
  //------------------------------------------------------------------------
  // This code block detects if INSTDRV already started and prevents start
  // of second copy.
    HWND hW;
    HWND hW_cfg;

    //Detect other running copy of the same Instdrv
    if ((hW = FindWindow( NULL, RS(S_TITLE)))!=NULL)
    {
        if ((hW_cfg = FindWindow( NULL, RS(S_TITLE_CFG)))!=NULL)
            SetForegroundWindow(hW_cfg);
        else
            SetForegroundWindow(hW);
        return 0;
    }
    //Now detect the older version of the Instdrv (with 'tm' on window hrader)
    if ((hW = FindWindow( NULL, RS(S_TITLE2)))!=NULL)
    {
        if ((hW_cfg = FindWindow( NULL, RS(S_TITLE_CFG2)))!=NULL)
            SetForegroundWindow(hW_cfg);
        else
            SetForegroundWindow(hW);
        return 0;
    }
 }

 //-------------------  Parsing the command line -----------------
 // Check: install or uninstall mode (/U)
 nCommand |= strstr( lpszCmdLine, "/U" ) ? COMMAND_UNINST : 0;

 // Check: quiet mode (/Q)
 bHide  = strstr( lpszCmdLine, "/Q"  ) ? TRUE : FALSE;

 // Check: always prompt for reboot
 bAlwaysAskForReboot = strstr( lpszCmdLine, "/RB"  ) ? TRUE : FALSE;

 // Check: do not reboot
 bSkipReboot = strstr( lpszCmdLine, "/NORB"  ) ? TRUE : FALSE;

 // Check: detailed error messages (/I)
 bInfo  = ((! bHide) && (strstr( lpszCmdLine, "/I" )) ? TRUE : FALSE);

 // Check: print log (/LOG)
 bPrintLog = (strstr( lpszCmdLine, "/LOG" )) ? TRUE : FALSE;

 // Check: set interface language
 if( strstr( lpszCmdLine, "/LR" ))       bRus=1000;
 if( strstr( lpszCmdLine, "/LE" ))       bRus=0;

 // Check /? || /H - display help screen
 if( strstr( lpszCmdLine, "/?" ) || strstr( lpszCmdLine, "/H" ) )
 {
        strcpy( szText,RS(S_INFO1));
        strcat( szText,RS(S_INFO2));
        MessageBox( NULL, szText, RS(S_TITLE), MB_ | MB_ICONINFORMATION  );
        return -1;
 }

 // Zerofill DrvState ....
 memset (&DrvState,sizeof(DrvState),0);

 // Set mode of displaying messages in dll

 dwConfigFlags  = (!bHide)?gic_SHOWMESSAGES:0;
 dwConfigFlags |= ( bInfo)?gic_FULLINFO:0;
 dwConfigFlags |= ( bPrintLog)?gic_PRINTLOG:0;
 dwConfigFlags |= gic_MANUALLANGUAGE;
 dwConfigFlags |= ( bRus)?0:gic_ENGLANGUAGE;


 GD_SetInstdrvConfig ( dwConfigFlags );

 // Detecting installed driver... Filling DI structure
 // (see DIALOG.C for implementation of this routine)
 nRet = CheckDriver();
 if ((nRet == ge_SOURCE_FILE_NOT_FOUND) ||
     (nRet == ge_DRIVER_BUSY))
 {
    GD_GetLastErrorDescription(szText,0x100);
    if ((!bHide)&&(!bInfo))
       MessageBox(NULL,szText,"Error ",MB_);
    if (nRet == ge_SOURCE_FILE_NOT_FOUND) 
       exit(3);
    if (nRet == ge_DRIVER_BUSY)
       exit(5);
 }

 // *********** Main fork: command line 'quiet' mode  *******
 // ***********  or dialog mode  ****************************
 if ( bHide )
 {
       if (!MakeOperation(nCommand))
           return 0;
       else
           return 3; //Unable to execute operation
 }
 else
 {
       // This cycle runs like: DIALOG -> OPERATION -> DIALOG -> ...

       while (1)
       {
          // This dialog returns if Install/ReInstall/Uninstall/Exit button is pressed
          //--------------------------------------------------
          nCommand = DialogBox(hMainInstance,MAKEINTRESOURCE(IDD_MSG),GetDesktopWindow(),(DLGPROC)MsgDlgProc);
          //--------------------------------------------------
          if (nCommand & COMMAND_EXIT) break; //Exit code...
          MakeOperation(nCommand);
          CheckDriver();	
       }
 }
  
 if ( DrvState.RebootNeeded )
    TryToExitWindows();

 GD_PrintLog ("-- INSTDRV finished successfuly");

 return 0;      // Ok

}


