//____________________________________________________________________________
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1995 - 1996.
//
//  File:       schdsrvc.cxx
//
//  Contents:
//
//  Notes:  Hack around the service not being started when creating tasks
//
//  Functions:	StartScheduler
//
//  History:    2/19/1997   SusiA   Cut from MSDN
//
//  Notes:      This function works for either Win9x or Windows NT.
//              If the service is running but paused, does nothing.//
//____________________________________________________________________________

#include "precomp.h"

extern OSVERSIONINFOA g_OSVersionInfo; 

#undef TRACE
#define TRACE(x)                //OutputDebugString(x)

#define MAX_SERVICE_WAIT_TIME   90000   //  a minute and a half

#define SCHED_CLASS             TEXT("SAGEWINDOWCLASS")
#define SCHED_TITLE             TEXT("SYSTEM AGENT COM WINDOW")
#define SCHED_SERVICE_APP_NAME  TEXT("mstask.exe")
#define SCHED_SERVICE_NAME      TEXT("Schedule")

DWORD StartScheduler()
{
    DWORD dwTimeOut;
    DWORD dwError;

    if (g_OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)    
	{
        // Start the Win9X version of TaskScheduler.
        HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE);
        
		if (hwnd != NULL)        
		{   // It is already running.
            return ERROR_SUCCESS;
        }        
		//
        //  Execute the task scheduler process.        
		//
        STARTUPINFO         sui;
        PROCESS_INFORMATION pi;
        ZeroMemory(&sui, sizeof(sui));
        sui.cb = sizeof (STARTUPINFO);
        
		TCHAR szApp[MAX_PATH];
        LPTSTR pszPath;
        
		DWORD dwRet = SearchPath(NULL,
                                 SCHED_SERVICE_APP_NAME,
                                 NULL,
                                 MAX_PATH,
                                 szApp,
                                 &pszPath);        
		if (dwRet == 0)        
		{
            return GetLastError();        
		}
        BOOL fRet = CreateProcess(szApp, NULL, NULL, NULL, FALSE,
                                  CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
                                  NULL,  NULL, &sui, &pi);

        if (fRet == 0)        
		{            
			return GetLastError();
        }

        //  Now that the process is started, let's wait until the window
        //  exists before we decide to return success.
        dwTimeOut = GetTickCount() + MAX_SERVICE_WAIT_TIME;
        dwError = ERROR_SERVICE_NEVER_STARTED;

        while (GetTickCount() < dwTimeOut)
        {
            if (FindWindow(SCHED_CLASS, SCHED_TITLE))
            {
                dwError = ERROR_SUCCESS;
                break;
            }
            Sleep(1000);
        }

        
		CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        
		return dwError;    
	}    
	else
    {
        // If not Win95 then start the NT version as a TaskScheduler service.
        SC_HANDLE   hSC = NULL;        
		SC_HANDLE   hSchSvc = NULL;
        hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
        if (hSC == NULL)        
		{            
			return GetLastError();
        }
        hSchSvc = OpenService(hSC,
                              SCHED_SERVICE_NAME,
                              SERVICE_START | SERVICE_QUERY_STATUS);

        CloseServiceHandle(hSC);
        if (hSchSvc == NULL)        
		{
            return GetLastError();        
		}        
		SERVICE_STATUS SvcStatus;
        
		if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE)        
		{
            CloseServiceHandle(hSchSvc);            
			return GetLastError();
        }        
		if (SvcStatus.dwCurrentState == SERVICE_RUNNING)        
		{
            // The service is already running.
            CloseServiceHandle(hSchSvc);
            return ERROR_SUCCESS;
        }
        if (StartService(hSchSvc, 0, NULL) == FALSE)
        {
            CloseServiceHandle(hSchSvc);
            return GetLastError();
        }

        dwTimeOut = GetTickCount() + MAX_SERVICE_WAIT_TIME;

        BOOL bContinue = TRUE;

        dwError = ERROR_SERVICE_NEVER_STARTED;

        while (bContinue)
        {
            if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE)
            {
                dwError = GetLastError();
                break;
            }

            switch (SvcStatus.dwCurrentState)
            {
                //  This is good!
                case SERVICE_RUNNING:
                    dwError = ERROR_SUCCESS;

                    //  Fall through

                //  These are bad
                case SERVICE_STOPPED:
                case SERVICE_STOP_PENDING:
                case SERVICE_PAUSE_PENDING:
                case SERVICE_PAUSED:
                    bContinue = FALSE;
                    break;

                default:
                    if (GetTickCount() < dwTimeOut)
                    {                        
                        //  How long to sleep?  According to the SDK use a tenth of the wait hint
                        //  and floor/ceil it between 1 and 10 seconds.

                        DWORD dwSleep = SvcStatus.dwWaitHint / 10;

                        if (dwSleep < 1000)
                        {
                            dwSleep = 1000;
                        }
                        else if (dwSleep > 10000)
                        {
                            dwSleep = 10000;
                        }
                        
                        TRACE("########## Waiting for Task Scheduler service to be started...\n");

                        Sleep(dwSleep);
                    }
                    else
                    {
                        TRACE("########## Starting Task Scheduler service timed out...\n");
                        bContinue = FALSE;
                    }
                    break;
            }
        }

        CloseServiceHandle(hSchSvc);

        TRACE("########## Stop waiting for Task Scheduler service to start...\n");

		return dwError;    
	}
}