412 lines
11 KiB
C++
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);
|
||
|
}
|
||
|
|