windows-nt/Source/XPSP1/NT/admin/services/sched/common/enable.cxx
2020-09-26 16:20:57 +08:00

412 lines
11 KiB
C++

//+----------------------------------------------------------------------------
//
// Scheduling Agent Service
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996.
//
// File: enable.cxx
//
// Contents: Code to enable/disable the service.
//
// Classes: None.
//
// Functions: StringFromTrigger, CreateFolders, GetDaysOfWeekString,
// GetExitCodeString, GetSageExitCodeString
//
// History: 10-Jun-96 EricB Created.
//
//-----------------------------------------------------------------------------
#include "..\pch\headers.hxx"
#pragma hdrstop
#include "..\inc\resource.h"
#include "..\inc\misc.hxx"
#include "..\inc\debug.hxx"
#include "..\..\inc\sadat.hxx"
HRESULT WillAnyJobsRun(void);
//+---------------------------------------------------------------------------
//
// Function: AutoStart
//
// Synopsis: Persists the autostart state in the registry.
//
// Arguments: [fAutoStart] - If true, service is set to autostart.
//
// Returns: HRESULTs
//
// Notes: FormatMessage allocates the return string. Use LocalFree() to
// deallocate.
//
// The "Run" key is written to on both platforms.
// The "RunServices" key is written to on _CHICAGO_ only.
// ChangeServiceConfig is called on NT only.
//
//----------------------------------------------------------------------------
HRESULT
AutoStart(BOOL fAutoStart)
{
schDebugOut((DEB_ITRACE, "AutoStart(%s)\n", fAutoStart ? "TRUE" : "FALSE"));
long lRet = 0;
HKEY hRunKey;
DWORD dwDisposition; // ignored
lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
REGSTR_PATH_RUN,
0, // reserved
NULL, // class
0, // non volatile
KEY_SET_VALUE,
NULL, // security attrs
&hRunKey,
&dwDisposition);
if (lRet != ERROR_SUCCESS)
{
ERR_OUT("AutoStart: RegCreateKeyEx of Run key", lRet);
return HRESULT_FROM_WIN32(lRet);
}
#if defined(_CHICAGO_)
HKEY hRunSvcKey;
lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
REGSTR_PATH_RUNSERVICES,
0, // reserved
NULL, // class
0, // non volatile
KEY_SET_VALUE,
NULL, // security attrs
&hRunSvcKey,
&dwDisposition);
if (lRet != ERROR_SUCCESS)
{
ERR_OUT("AutoStart: RegCreateKeyEx of RunServices key", lRet);
RegCloseKey(hRunKey);
return HRESULT_FROM_WIN32(lRet);
}
#endif // _CHICAGO_
if (fAutoStart)
{
//
// Set the startup values.
//
#if defined(_CHICAGO_)
lRet = RegSetValueEx(hRunSvcKey,
SCH_RUN_VALUE,
0,
REG_SZ,
(CONST BYTE *) SCHED_SERVICE_APP_NAME,
sizeof(SCHED_SERVICE_APP_NAME));
if (lRet != ERROR_SUCCESS)
{
ERR_OUT("AutoStart: RegSetValueEx of RunServices key value", lRet);
goto Cleanup0;
}
#endif // _CHICAGO_
#define LogonValue SCHED_SETUP_APP_NAME TEXT(" ") SCHED_FIRSTLOGON_SWITCH
lRet = RegSetValueEx(hRunKey,
SCH_RUN_VALUE,
0,
REG_SZ,
(CONST BYTE *) LogonValue,
sizeof(LogonValue));
if (lRet != ERROR_SUCCESS)
{
ERR_OUT("AutoStart: RegSetValueEx of Run key value", lRet);
goto Cleanup0;
}
}
else
{
//
// Clear the startup values to disable autostart.
//
#if defined(_CHICAGO_)
lRet = RegDeleteValue(hRunSvcKey, SCH_RUN_VALUE);
if (lRet != ERROR_SUCCESS && lRet != ERROR_FILE_NOT_FOUND)
{
ERR_OUT("AutoStart: RegDeleteValue of RunService key value", lRet);
goto Cleanup0;
}
#endif // _CHICAGO_
lRet = RegDeleteValue(hRunKey, SCH_RUN_VALUE);
if (lRet != ERROR_SUCCESS && lRet != ERROR_FILE_NOT_FOUND)
{
ERR_OUT("AutoStart: RegDeleteValue of Run key value", lRet);
goto Cleanup0;
}
}
Cleanup0:
#if defined(_CHICAGO_)
RegCloseKey(hRunSvcKey);
#endif // _CHICAGO_
RegCloseKey(hRunKey);
if (lRet != ERROR_SUCCESS)
{
return HRESULT_FROM_WIN32(lRet);
}
#if !defined(_CHICAGO_)
SC_HANDLE hSC, hSvc;
hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | GENERIC_WRITE);
if (hSC == NULL)
{
lRet = GetLastError();
ERR_OUT("AutoStart: OpenSCManager", lRet);
return HRESULT_FROM_WIN32(lRet);
}
hSvc = OpenService(hSC, g_tszSrvcName, SERVICE_CHANGE_CONFIG);
if (hSvc == NULL)
{
lRet = GetLastError();
ERR_OUT("AutoStart: OpenService", lRet);
CloseServiceHandle(hSC);
return HRESULT_FROM_WIN32(lRet);
}
if (ChangeServiceConfig(hSvc,
SERVICE_NO_CHANGE,
fAutoStart ? SERVICE_AUTO_START :
SERVICE_DEMAND_START,
SERVICE_NO_CHANGE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL) == FALSE)
{
lRet = GetLastError();
ERR_OUT("AutoStart: ChangeServiceConfig", lRet);
}
CloseServiceHandle(hSvc);
CloseServiceHandle(hSC);
#endif // !defined(_CHICAGO_)
return (lRet != 0) ? HRESULT_FROM_WIN32(lRet) : S_OK;
}
//+----------------------------------------------------------------------------
//
// Member: WillAnyJobsRun
//
// Synopsis: Examines the job objects in the scheduler folder to see if any
// will run at some point in the future.
//
// Returns: S_OK if any jobs will run, S_FALSE if no jobs will run, or an
// error code.
//
// Notes: This function is called only during setup; however, it is in
// the task DLL, rather than the setup EXE, in order to avoid
// exporting the CJob methods from the DLL.
//
//-----------------------------------------------------------------------------
HRESULT
WillAnyJobsRun(void)
{
TRACE_FUNCTION(WillAnyJobsRun);
HRESULT hr = S_OK;
DWORD dwRet;
HANDLE hFind;
WIN32_FIND_DATA fd;
//
// Compose the job search string. It will be composed of the following:
// g_TasksFolderInfo.ptszPath\*.TSZ_JOB
//
TCHAR tszPath[MAX_PATH + MAX_PATH];
lstrcpy(tszPath, g_TasksFolderInfo.ptszPath);
lstrcat(tszPath, TEXT("\\*.") TSZ_JOB);
hFind = FindFirstFile(tszPath, &fd);
if (hFind == INVALID_HANDLE_VALUE)
{
dwRet = GetLastError();
if (dwRet == ERROR_FILE_NOT_FOUND)
{
//
// No job files.
//
return S_FALSE;
}
else
{
ERR_OUT("WillAnyJobsRun FindFirstFile", dwRet);
return HRESULT_FROM_WIN32(dwRet);
}
}
SYSTEMTIME stNow;
GetLocalTime(&stNow);
CJob * pJob = CJob::Create();
if (pJob == NULL)
{
ERR_OUT("WillAnyJobsRun CJob::Create", E_OUTOFMEMORY);
return E_OUTOFMEMORY;
}
do
{
schDebugOut((DEB_ITRACE, "Found job " FMT_TSTR "\n", fd.cFileName));
//
// TODO: differentiate between job and queue objects and handle
// accordingly.
//
lstrcpy(tszPath, g_TasksFolderInfo.ptszPath);
lstrcat(tszPath, TEXT("\\"));
lstrcat(tszPath, fd.cFileName);
hr = pJob->LoadP(tszPath, 0, TRUE, FALSE);
if (FAILED(hr))
{
ERR_OUT("WillAnyJobsRun LoadP", hr);
hr = S_OK;
goto CheckNextJob;
}
//
// Check if job can run.
//
DWORD dwFlags;
pJob->GetAllFlags(&dwFlags);
if (!(dwFlags & TASK_FLAG_DISABLED) &&
(dwFlags & JOB_I_FLAG_HAS_APPNAME))
{
//
// LoadTriggers will set or clear the JOB_I_FLAG_HAS_TRIGGERS flag
// as appropriate.
//
hr = pJob->LoadTriggers();
if (FAILED(hr))
{
ERR_OUT("WillAnyJobsRun, pJob->LoadTriggers", hr);
hr = S_OK;
goto CheckNextJob;
}
pJob->GetAllFlags(&dwFlags);
if (dwFlags & JOB_I_FLAG_HAS_TRIGGERS)
{
WORD cRuns = 0;
hr = pJob->GetRunTimesP(&stNow, NULL, &cRuns, 1, NULL, NULL);
if (FAILED(hr))
{
ERR_OUT("WillAnyJobsRun GetRunTimes", hr);
hr = S_OK;
goto CheckNextJob;
}
if (cRuns > 0 || hr == SCHED_S_EVENT_TRIGGER)
{
//
// Finding one is sufficent, lets go home.
//
pJob->Release();
FindClose(hFind);
return S_OK;
}
}
}
CheckNextJob:
if (!FindNextFile(hFind, &fd))
{
dwRet = GetLastError();
if (dwRet == ERROR_NO_MORE_FILES)
{
break;
}
else
{
ERR_OUT("CSchedWorker::WillAnyJobsRun, FindNextFile", dwRet);
hr = HRESULT_FROM_WIN32(dwRet);
goto Cleanup;
}
}
}
while (SUCCEEDED(hr));
Cleanup:
pJob->Release();
FindClose(hFind);
return (FAILED(hr)) ? hr : S_FALSE;
}
//+----------------------------------------------------------------------------
//
// Member: ConditionallyEnableService
//
// Synopsis: If any of the job objects in the scheduler folder will run at
// some point in the future, then the service is enabled.
// Otherwise, it is disabled.
//
// History: 1-15-1997 DavidMun Call SADatCreate if service not
// enabled.
//
//-----------------------------------------------------------------------------
STDAPI_(BOOL)
ConditionallyEnableService(void)
{
BOOL fEnable;
DWORD dwVersion; // For SADatGetData
BYTE bPlatform, brgSvcFlags;
HRESULT hr;
#ifdef _CHICAGO_
fEnable = (WillAnyJobsRun() == S_OK);
#else
fEnable = TRUE;
#endif
AutoStart(fEnable);
hr = SADatGetData(g_TasksFolderInfo.ptszPath,
&dwVersion,
&bPlatform,
&brgSvcFlags);
if (FAILED(hr))
{
brgSvcFlags = 0;
}
//
// The SA.DAT file must be present for the UI to work properly. It
// is created on service start, but if the service isn't enabled,
// the user may open the UI and see the wrong thing. So create the
// file here.
//
hr = SADatCreate(g_TasksFolderInfo.ptszPath,
(BOOL)brgSvcFlags & SA_DAT_SVCFLAG_SVC_RUNNING);
if (FAILED(hr))
{
ERR_OUT("ConditionallyEnableService, SADatCreate", hr);
}
return(fEnable);
}