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

1470 lines
35 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1994 - 1996.
//
// File: util.cxx
//
// Contents: Miscellaneous utility functions.
//
// History: 04-04-95 DavidMun Created
//
//----------------------------------------------------------------------------
#include <headers.hxx>
#pragma hdrstop
#include <msterr.h>
#include "jt.hxx"
//
// Local constants
//
const ULONG MONTH_INDEX_JAN = 0;
const ULONG MONTH_INDEX_FEB = 1;
const ULONG MONTH_INDEX_MAR = 2;
const ULONG MONTH_INDEX_APR = 3;
const ULONG MONTH_INDEX_MAY = 4;
const ULONG MONTH_INDEX_JUN = 5;
const ULONG MONTH_INDEX_JUL = 6;
const ULONG MONTH_INDEX_AUG = 7;
const ULONG MONTH_INDEX_SEP = 8;
const ULONG MONTH_INDEX_OCT = 9;
const ULONG MONTH_INDEX_NOV = 10;
const ULONG MONTH_INDEX_DEC = 11;
const ULONG MONTHS_PER_YEAR = 12;
//+---------------------------------------------------------------------------
//
// Function: GetPriorityString
//
// Synopsis: Return a human-readable string representing [dwPriority].
//
// Arguments: [dwPriority] - process priority
//
// Returns: static string
//
// History: 01-03-96 DavidMun Created
//
//----------------------------------------------------------------------------
LPCSTR GetPriorityString(DWORD dwPriority)
{
switch (dwPriority)
{
case IDLE_PRIORITY_CLASS:
return "IDLE";
case NORMAL_PRIORITY_CLASS:
return "NORMAL";
case HIGH_PRIORITY_CLASS:
return "HIGH";
case REALTIME_PRIORITY_CLASS:
return "REALTIME";
}
return "INVALID PRIORITY";
}
//+---------------------------------------------------------------------------
//
// Function: GetMonthsString
//
// Synopsis: Return a static string containing month names for each month
// bit turned on in [rgfMonths]
//
// Arguments: [rgfMonths] - TASK_JANUARY | TASK_FEBRUARY | ... |
// TASK_DECEMBER
//
// Returns: static string
//
// History: 03-07-96 DavidMun Created
//
//----------------------------------------------------------------------------
LPCWSTR GetMonthsString(WORD rgfMonths)
{
static WCHAR s_wszMonths[MONTHS_PER_YEAR * MONTH_ABBREV_LEN + 1];
s_wszMonths[0] = '\0';
if (rgfMonths & TASK_JANUARY)
{
wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_JAN]);
}
if (rgfMonths & TASK_FEBRUARY)
{
wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_FEB]);
}
if (rgfMonths & TASK_MARCH)
{
wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_MAR]);
}
if (rgfMonths & TASK_APRIL)
{
wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_APR]);
}
if (rgfMonths & TASK_MAY)
{
wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_MAY]);
}
if (rgfMonths & TASK_JUNE)
{
wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_JUN]);
}
if (rgfMonths & TASK_JULY)
{
wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_JUL]);
}
if (rgfMonths & TASK_AUGUST)
{
wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_AUG]);
}
if (rgfMonths & TASK_SEPTEMBER)
{
wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_SEP]);
}
if (rgfMonths & TASK_OCTOBER)
{
wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_OCT]);
}
if (rgfMonths & TASK_NOVEMBER)
{
wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_NOV]);
}
if (rgfMonths & TASK_DECEMBER)
{
wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_DEC]);
}
if (s_wszMonths[0] == '\0')
{
wcscpy(s_wszMonths, L"None");
}
return s_wszMonths;
}
//+---------------------------------------------------------------------------
//
// Function: DumpJobFlags
//
// Synopsis: Dump description of [flJobFlags] to log.
//
// Arguments: [flJobFlags] - TASK_*
//
// History: 01-03-96 DavidMun Created
//
//----------------------------------------------------------------------------
VOID DumpJobFlags(DWORD flJobFlags)
{
#ifndef RES_KIT
g_Log.Write(
LOG_TEXT,
" Interactive = %u",
(flJobFlags & TASK_FLAG_INTERACTIVE) != 0);
#endif
g_Log.Write(
LOG_TEXT,
" DeleteWhenDone = %u",
(flJobFlags & TASK_FLAG_DELETE_WHEN_DONE) != 0);
g_Log.Write(
LOG_TEXT,
" Suspend = %u",
(flJobFlags & TASK_FLAG_DISABLED) != 0);
g_Log.Write(
LOG_TEXT,
" StartOnlyIfIdle = %u",
(flJobFlags & TASK_FLAG_START_ONLY_IF_IDLE) != 0);
g_Log.Write(
LOG_TEXT,
" KillOnIdleEnd = %u",
(flJobFlags & TASK_FLAG_KILL_ON_IDLE_END) != 0);
g_Log.Write(
LOG_TEXT,
" RestartOnIdleResume = %u",
(flJobFlags & TASK_FLAG_RESTART_ON_IDLE_RESUME) != 0);
g_Log.Write(
LOG_TEXT,
" DontStartIfOnBatteries = %u",
(flJobFlags & TASK_FLAG_DONT_START_IF_ON_BATTERIES) != 0);
g_Log.Write(
LOG_TEXT,
" KillIfGoingOnBatteries = %u",
(flJobFlags & TASK_FLAG_KILL_IF_GOING_ON_BATTERIES) != 0);
g_Log.Write(
LOG_TEXT,
" RunOnlyIfLoggedOn = %u",
(flJobFlags & TASK_FLAG_RUN_ONLY_IF_LOGGED_ON) != 0);
g_Log.Write(
LOG_TEXT,
" SystemRequired = %u",
(flJobFlags & TASK_FLAG_SYSTEM_REQUIRED) != 0);
g_Log.Write(
LOG_TEXT,
" Hidden = %u",
(flJobFlags & TASK_FLAG_HIDDEN) != 0);
flJobFlags = flJobFlags &
~(TASK_FLAG_INTERACTIVE |
TASK_FLAG_DELETE_WHEN_DONE |
TASK_FLAG_DISABLED |
TASK_FLAG_START_ONLY_IF_IDLE |
TASK_FLAG_KILL_ON_IDLE_END |
TASK_FLAG_RESTART_ON_IDLE_RESUME |
TASK_FLAG_DONT_START_IF_ON_BATTERIES |
TASK_FLAG_KILL_IF_GOING_ON_BATTERIES |
TASK_FLAG_RUN_ONLY_IF_LOGGED_ON |
TASK_FLAG_SYSTEM_REQUIRED |
TASK_FLAG_HIDDEN);
if (flJobFlags)
{
g_Log.Write(LOG_WARN, " Unrecognized bits = %x", flJobFlags);
}
}
//+---------------------------------------------------------------------------
//
// Function: DumpTriggers
//
// Synopsis: Print all triggers to the log.
//
// Arguments: [fJob] - TRUE=>print g_pJob triggers, FALSE=> use g_pJobQueue
//
// Returns: S_OK - all triggers printed
// E_* - error printing a trigger
//
// History: 01-10-96 DavidMun Created
//
//----------------------------------------------------------------------------
HRESULT DumpTriggers(BOOL fJob)
{
HRESULT hr = S_OK;
USHORT i;
USHORT cTriggers;
do
{
if (fJob)
{
hr = g_pJob->GetTriggerCount(&cTriggers);
LOG_AND_BREAK_ON_FAIL(hr, "ITask::GetTriggerCount");
}
else
{
#ifdef NOT_YET
hr = g_pJobQueue->GetTriggerCount(&cTriggers);
LOG_AND_BREAK_ON_FAIL(hr, "ITaskQueue::GetTriggerCount");
#endif // NOT_YET
hr = E_NOTIMPL;
}
g_Log.Write(LOG_TEXT, "");
if (!cTriggers)
{
g_Log.Write(LOG_TEXT, " No triggers");
break;
}
g_Log.Write(
LOG_TEXT,
" %u Trigger%c",
cTriggers,
cTriggers == 1 ? ' ' : 's');
for (i = 0; i < cTriggers; i++)
{
hr = DumpTrigger(fJob, i);
}
}
while (0);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: DumpJob
//
// Synopsis: Write all job properties to the log.
//
// Arguments: [pJob] - job to dump
//
// Returns: S_OK - printed
// E_* - couldn't read all job properties
//
// History: 03-11-96 DavidMun Created
//
//----------------------------------------------------------------------------
HRESULT DumpJob(ITask *pJob)
{
HRESULT hr = S_OK;
CJobProp JobProperties;
do
{
g_Log.Write(LOG_TRACE, "Printing all job properties");
//
// Print the properties of the job itself first
//
hr = JobProperties.InitFromActual(pJob);
BREAK_ON_FAILURE(hr);
JobProperties.Dump();
}
while (0);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: DumpJobTriggers
//
// Synopsis: Write properties of all triggers on job to the log.
//
// Arguments: [pJob] - job for which to write trigger properties to log
//
// Returns: S_OK - information printed
// E_* - couldn't read all trigger properties
//
// History: 03-11-96 DavidMun Created
//
//----------------------------------------------------------------------------
HRESULT DumpJobTriggers(ITask *pJob)
{
HRESULT hr = S_OK;
USHORT i;
USHORT cTriggers;
do
{
hr = pJob->GetTriggerCount(&cTriggers);
LOG_AND_BREAK_ON_FAIL(hr, "ITask::GetTriggerCount");
g_Log.Write(LOG_TEXT, "");
if (!cTriggers)
{
g_Log.Write(LOG_TEXT, " No triggers");
break;
}
g_Log.Write(
LOG_TEXT,
" %u Trigger%c",
cTriggers,
cTriggers == 1 ? ' ' : 's');
for (i = 0; i < cTriggers; i++)
{
SpIJobTrigger spTrigger;
CTrigProp TriggerProperties;
hr = pJob->GetTrigger(i, &spTrigger);
LOG_AND_BREAK_ON_FAIL(hr, "ITask::GetTrigger");
hr = TriggerProperties.InitFromActual(spTrigger);
BREAK_ON_FAILURE(hr);
g_Log.Write(LOG_TEXT, "");
g_Log.Write(LOG_TEXT, " Trigger %u:", i);
TriggerProperties.Dump();
}
}
while (0);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: DumpTrigger
//
// Synopsis: Print a single trigger to the log
//
// Arguments: [fJob] - TRUE=>print g_pJob triggers,
// FALSE=> use g_pJobQueue
// [usTrigger] - 0-based trigger index
//
// Returns: S_OK - trigger printed
// E_* - error printing a trigger
//
// History: 01-10-96 DavidMun Created
//
//----------------------------------------------------------------------------
HRESULT DumpTrigger(BOOL fJob, USHORT usTrigger)
{
HRESULT hr = S_OK;
SpIJobTrigger spTrigger;
CTrigProp TriggerProperties;
do
{
if (fJob)
{
hr = g_pJob->GetTrigger(usTrigger, &spTrigger);
LOG_AND_BREAK_ON_FAIL(hr, "ITask::GetTrigger");
}
else
{
#ifdef NOT_YET
hr = g_pJobQueue->GetTrigger(usTrigger, &spTrigger);
LOG_AND_BREAK_ON_FAIL(hr, "ITaskQueue::GetTrigger");
#endif // NOT_YET
hr = E_NOTIMPL;
}
hr = TriggerProperties.InitFromActual(spTrigger);
BREAK_ON_FAILURE(hr);
g_Log.Write(LOG_TEXT, "");
g_Log.Write(LOG_TEXT, " Trigger %u:", usTrigger);
TriggerProperties.Dump();
}
while (0);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: GetInterfaceString
//
// Synopsis: Return string in the form IID_* or "unrecognized interface"
//
// Arguments: [iidToBind] - interface
//
// History: 04-25-95 DavidMun Created
// 09-11-95 DavidMun New interfaces
//
//----------------------------------------------------------------------------
LPCSTR GetInterfaceString(REFIID iid)
{
CHAR *szInterface;
if (&iid == &IID_IUnknown)
{
szInterface = "IID_IUnknown";
}
else if (&iid == &IID_ITask)
{
szInterface = "IID_ITask";
}
else if (&iid == &IID_ITaskTrigger)
{
szInterface = "IID_ITaskTrigger";
}
else
{
szInterface = "unrecognized interface";
}
return szInterface;
}
//+---------------------------------------------------------------------------
//
// Function: GetTriggerTypeString
//
// Synopsis: Return a static human-readable string describing
// [TriggerType].
//
// Arguments: [TriggerType] - TASK_TRIGGER_TYPE
//
// Returns: static string
//
// History: 01-04-96 DavidMun Created
// 06-13-96 DavidMun Logon trigger
//
//----------------------------------------------------------------------------
LPCSTR GetTriggerTypeString(TASK_TRIGGER_TYPE TriggerType)
{
switch (TriggerType)
{
case TASK_TIME_TRIGGER_ONCE:
return "Once";
case TASK_TIME_TRIGGER_DAILY:
return "Daily";
case TASK_TIME_TRIGGER_WEEKLY:
return "Weekly";
case TASK_TIME_TRIGGER_MONTHLYDATE:
return "MonthlyDate";
case TASK_TIME_TRIGGER_MONTHLYDOW:
return "MonthlyDOW";
case TASK_EVENT_TRIGGER_ON_IDLE:
return "OnIdle";
case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
return "AtStartup";
case TASK_EVENT_TRIGGER_AT_LOGON:
return "AtLogon";
}
return "INVALID TRIGGER TYPE";
}
//+---------------------------------------------------------------------------
//
// Function: GetDaysString
//
// Synopsis: Returns static string representing day bits in
// [rgfDays].
//
// Arguments: [rgfDays] - each of the 32 bits corresponds to a day of the
// month.
//
// Returns: static string
//
// History: 03-07-96 DavidMun Created
//
// Notes: This routine supports "day 32" because if the job scheduler
// erroneously turns on that bit we want to make it visible.
//
//----------------------------------------------------------------------------
LPCSTR GetDaysString(DWORD rgfDays)
{
static CHAR s_szDaysList[] =
"1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,32";
ULONG i;
ULONG j;
ULONG ulRunStart = 0;
BOOL fInRun = FALSE;
//
// Note s_szDaysList is initialized to worst case to get adequately long
// string. The most significant bit may be set and we want to display
// that, so it includes space for 32.
//
s_szDaysList[0] = '\0';
for (i = 0; i <= 32; i++, rgfDays >>= 1)
{
if (rgfDays & 1)
{
//
// Day 'i' should be included in the string. If we're in a run of
// days that are on, simply continue. When the run ends we'll add
// it to the string.
//
// If we're not in a run of days, consider this day the start of
// a new run (which may turn out to be only one day long).
//
if (!fInRun)
{
fInRun = TRUE;
ulRunStart = i;
}
}
else if (fInRun)
{
//
// Bit i is a zero, so obviously we're not in a run of ones
// anymore. Turn off that flag.
//
fInRun = FALSE;
//
// The bits from ulRunStart to i-1 were all on. Find out if the
// run was just one or two bits long, if that's the case then
// we don't want to use the m-n list form, the day number(s) should
// simply be appended to the string.
//
// Note that at this point i must be >= 1.
//
if (i == 1)
{
// ulRunStart == 0. bit 0 was on, which corresponds to day 1.
strcpy(s_szDaysList, "1");
}
else if (i == 2)
{
//
// ulRunStart == 0 or 1, so the run is 1 or 2 bits long. So
// we don't want to use a dash.
//
if (ulRunStart == 0)
{
strcpy(s_szDaysList, "1,2");
}
else
{
strcpy(s_szDaysList, "2");
}
}
else if (ulRunStart <= i - 3) // i >= 3 at this point
{
// There's a run of > 2 bits, which means we want a dash
if (s_szDaysList[0])
{
strcat(s_szDaysList, ",");
}
//
// Remember we're converting from a bit position, which is 0
// based, to a day number, which is 1 based.
//
CHAR *pszNext;
pszNext = s_szDaysList + strlen(s_szDaysList);
pszNext += wsprintfA(pszNext, "%u", ulRunStart + 1);
*pszNext++ = '-';
wsprintfA(pszNext, "%u", i);
}
else
{
// There's a run of 1 or 2 bits
CHAR *pszNext = s_szDaysList + strlen(s_szDaysList);
for (j = ulRunStart; j < i; j++)
{
if (s_szDaysList[0])
{
*pszNext++ = ',';
}
pszNext += wsprintfA(pszNext, "%u", j+1);
}
}
}
}
return s_szDaysList;
}
//+---------------------------------------------------------------------------
//
// Function: GetDaysOfWeekString
//
// Synopsis: Returns static string representing day bits in
// [flDaysOfTheWeek].
//
// Arguments: [flDaysOfTheWeek] - TASK_*DAY bits
//
// Returns: static string
//
// History: 01-04-96 DavidMun Created
//
//----------------------------------------------------------------------------
LPCSTR GetDaysOfWeekString(WORD flDaysOfTheWeek)
{
static CHAR s_szDOW[] = "UMTWRFA"; // init to get max size
sprintf(s_szDOW, ".......");
if (flDaysOfTheWeek & TASK_SUNDAY)
{
s_szDOW[0] = 'U';
}
if (flDaysOfTheWeek & TASK_MONDAY)
{
s_szDOW[1] = 'M';
}
if (flDaysOfTheWeek & TASK_TUESDAY)
{
s_szDOW[2] = 'T';
}
if (flDaysOfTheWeek & TASK_WEDNESDAY)
{
s_szDOW[3] = 'W';
}
if (flDaysOfTheWeek & TASK_THURSDAY)
{
s_szDOW[4] = 'R';
}
if (flDaysOfTheWeek & TASK_FRIDAY)
{
s_szDOW[5] = 'F';
}
if (flDaysOfTheWeek & TASK_SATURDAY)
{
s_szDOW[6] = 'A';
}
return s_szDOW;
}
//+---------------------------------------------------------------------------
//
// Function: GetStatusString
//
// Synopsis: Return a string describing job status.
//
// Arguments: [hrJobStatus] - SCHED_* hresult
//
// Returns: static string
//
// History: 01-08-96 DavidMun Created
//
//----------------------------------------------------------------------------
LPCSTR GetStatusString(HRESULT hrJobStatus)
{
static CHAR s_szStatus[11]; // big enough for 0x00000000
switch (hrJobStatus)
{
case S_OK:
return "S_OK";
case SCHED_S_TASK_READY:
return "SCHED_S_TASK_READY";
case SCHED_S_TASK_RUNNING:
return "SCHED_S_TASK_RUNNING";
case SCHED_S_TASK_DISABLED:
return "SCHED_S_TASK_DISABLED";
case SCHED_S_TASK_TERMINATED:
return "SCHED_S_TASK_TERMINATED";
case SCHED_S_TASK_HAS_NOT_RUN:
return "SCHED_S_TASK_HAS_NOT_RUN";
case SCHED_S_TASK_NO_VALID_TRIGGERS:
return "SCHED_S_TASK_NO_VALID_TRIGGERS";
case SCHED_S_TASK_NO_MORE_RUNS:
return "SCHED_S_TASK_NO_MORE_RUNS";
case SCHED_S_TASK_NOT_SCHEDULED:
return "SCHED_S_TASK_NOT_SCHEDULED";
case SCHED_E_TASK_NOT_RUNNING:
return "SCHED_E_TASK_NOT_RUNNING";
case SCHED_E_SERVICE_NOT_INSTALLED:
return "SCHED_E_SERVICE_NOT_INSTALLED";
case SCHED_E_ACCOUNT_INFORMATION_NOT_SET:
return "SCHED_E_ACCOUNT_INFORMATION_NOT_SET";
#ifdef DELETED
case SCHED_E_NOT_AN_AT_JOB:
return "SCHED_E_NOT_AN_AT_JOB";
#endif // DELETED
default:
sprintf(s_szStatus, "%#x", hrJobStatus);
return s_szStatus;
}
}
//+---------------------------------------------------------------------------
//
// Function: Bind
//
// Synopsis: Bind to [wszFilename] for [iidToBind].
//
// Arguments: [wszFilename] - file to bind to
// [iidToBind] - interface to request
// [ppitf] - resulting interface
//
// Returns: S_OK - *[ppitf] valid
// E_* - error logged
//
// Modifies: *[ppitf]
//
// History: 04-20-95 DavidMun Created
// 04-25-95 DavidMun Add performance output
//
//----------------------------------------------------------------------------
HRESULT Bind(WCHAR *wszFilename, REFIID iidToBind, VOID **ppitf)
{
HRESULT hr = S_OK;
SpIMoniker spmk;
ULONG ulTicks;
do
{
g_Log.Write(
LOG_DEBUG,
"Binding to %S for %s",
wszFilename,
GetInterfaceString(iidToBind));
hr = GetMoniker(wszFilename, &spmk);
BREAK_ON_FAILURE(hr);
ulTicks = GetTickCount();
hr = BindMoniker(spmk, 0, iidToBind, ppitf);
ulTicks = GetTickCount() - ulTicks;
g_Log.Write(
LOG_PERF,
"Bind to %S for %s %u ms",
wszFilename,
GetInterfaceString(iidToBind),
ulTicks);
if (FAILED(hr))
{
g_Log.Write(
LOG_FAIL,
"BindMoniker to \"%S\" hr=%#010x",
wszFilename,
hr);
}
}
while (0);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: GetMoniker
//
// Synopsis: Return a filemoniker to [wszFilename].
//
// Arguments: [wszFilename] - file to get moniker for
// [ppmk] - resulting moniker
//
// Returns: S_OK - *[ppmk] valid
// E_* - error logged
//
// Modifies: *[ppmk]
//
// History: 04-20-95 DavidMun Created
//
//----------------------------------------------------------------------------
HRESULT GetMoniker(WCHAR *wszFilename, IMoniker **ppmk)
{
HRESULT hr = S_OK;
do
{
g_Log.Write(LOG_DEBUG, "Creating file moniker to %S", wszFilename);
hr = CreateFileMoniker(wszFilename, ppmk);
if (FAILED(hr))
{
g_Log.Write(
LOG_FAIL,
"CreateFileMoniker(\"%S\") hr=%#010x",
wszFilename,
hr);
break;
}
}
while (0);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: DupString
//
// Synopsis: Fill *[ppwszDest] with a buffer containing a copy of
// [wszSource].
//
// Arguments: [wszSource] - string to copy
// [ppwszDest] - filled with buffer containing copy
//
// Returns: S_OK
// E_OUTOFMEMORY;
//
// Modifies: *[ppwszDest]
//
// History: 04-20-95 DavidMun Created
//
// Notes: Caller must use delete to free *[ppwszDest].
//
//----------------------------------------------------------------------------
HRESULT DupString(const WCHAR *wszSource, WCHAR **ppwszDest)
{
HRESULT hr = S_OK;
*ppwszDest = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * (1 + wcslen(wszSource)));
if (!*ppwszDest)
{
hr = E_OUTOFMEMORY;
g_Log.Write(LOG_ERROR, "DupString: out of memory");
}
else
{
wcscpy(*ppwszDest, wszSource);
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HasFilename
//
// Synopsis: Return S_OK if object has filename, S_FALSE if not.
//
// Arguments: [pPersistFile] - IPFile itf on object
//
// Returns: S_OK - object has filename
// S_FALSE - object does not have filename
// E_* - error logged
//
// History: 01-10-96 DavidMun Created
//
//----------------------------------------------------------------------------
HRESULT HasFilename(IPersistFile *pPersistFile)
{
HRESULT hr = S_OK;
LPOLESTR pstrFile;
do
{
hr = pPersistFile->GetCurFile(&pstrFile);
LOG_AND_BREAK_ON_FAIL(hr, "IPersistFile::GetCurFile");
CoTaskMemFree(pstrFile);
}
while (0);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: SaveIfDirty
//
// Synopsis: Save given job object if it's dirty.
//
// Arguments: [pJob] - job to save
//
// Returns: S_OK - not dirty or successfully saved
// E_* - error logged
//
// History: 01-10-96 DavidMun Created
//
//----------------------------------------------------------------------------
HRESULT SaveIfDirty(ITask *pJob)
{
HRESULT hr = S_OK;
SpIPersistFile spPersistFile;
do
{
hr = pJob->QueryInterface(IID_IPersistFile, (void **)&spPersistFile);
LOG_AND_BREAK_ON_FAIL(hr, "ITask::QI(IPersistFile)");
hr = _SaveIfDirty(spPersistFile);
}
while (0);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: SaveIfDirty
//
// Synopsis: Save queue object if it's dirty. See job object version.
//
// History: 01-10-96 DavidMun Created
//
//----------------------------------------------------------------------------
HRESULT SaveIfDirty(IUnknown *pJobQueue)
{
HRESULT hr = S_OK;
SpIPersistFile spPersistFile;
do
{
hr = pJobQueue->QueryInterface(
IID_IPersistFile,
(void **)&spPersistFile);
LOG_AND_BREAK_ON_FAIL(hr, "ITaskQueue::QI(IPersistFile)");
hr = _SaveIfDirty(spPersistFile);
}
while (0);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: _SaveIfDirty
//
// Synopsis: Save persisted object if it reports it's dirty.
//
// Arguments: [pPersistFile] - IPFile on job or queue
//
// Returns: S_OK - saved or not dirty
// E_* - error logged
//
// History: 01-10-96 DavidMun Created
//
//----------------------------------------------------------------------------
HRESULT _SaveIfDirty(IPersistFile *pPersistFile)
{
HRESULT hr = S_OK;
do
{
hr = HasFilename(pPersistFile);
BREAK_ON_FAILURE(hr);
//
// If the object doesn't have a filename then it can't be persisted.
//
if (hr == S_FALSE)
{
break;
}
//
// If the object isn't dirty, there's nothing to do
//
hr = pPersistFile->IsDirty();
LOG_AND_BREAK_ON_FAIL(hr, "IPersistFile::IsDirty");
if (hr == S_FALSE)
{
break;
}
//
// Save the object.
//
hr = pPersistFile->Save(NULL, TRUE);
LOG_AND_BREAK_ON_FAIL(hr, "IPersistFile::Save");
}
while (0);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: Activate
//
// Synopsis: Perform the Activate command
//
// Arguments: [wszFileName] - name of job or queue to activate
// [ppJob] - filled if file is job
// [ppQueue] - filled if file is queue
// [pfJob] - set TRUE if [wszFileName] is a job, FALSE
// otherwise.
//
// Returns: S_OK - *[pfJob] and either *[ppJob] or *[ppQueue] valid
// E_* - error logged
//
// Modifies: *[pfJob], and either *[ppJob] or *[ppQueue]
//
// History: 01-30-96 DavidMun Created
//
//----------------------------------------------------------------------------
HRESULT Activate(
WCHAR *wszFileName,
ITask **ppJob,
IUnknown **ppQueue,
BOOL *pfJob)
{
HRESULT hr = S_OK;
SpIJob spJob;
SpIUnknown spQueue;
do
{
*pfJob = TRUE;
//
// BUGBUG remove this ifdef when ITaskScheduler::IsTask() and
// ITaskScheduler::IsQueue() are implemented.
//
#ifdef IS_JOB_IMPLEMENTED
hr = g_pJobScheduler->IsJob(wszFileName);
LOG_AND_BREAK_ON_FAIL(hr, "ITaskScheduler::IsTask");
if (hr == S_FALSE)
{
hr = g_pJobScheduler->IsQueue(wszFileName);
if (hr == S_OK)
{
*pfJob = FALSE;
}
else
{
g_Log.Write(
LOG_FAIL,
"File '%S' is neither a job nor a queue, IsJob hr=S_FALSE, IsQueue hr=%#010x",
wszFilename,
hr);
hr = E_FAIL;
break;
}
}
else if (hr != S_OK)
{
g_pLog->Write(
LOG_FAIL,
"Unexpected hr from IsJob: %#010x", hr);
hr = E_FAIL;
break;
}
#endif // IS_JOB_IMPLEMENTED
//
// Activate the job or queue and ask for the appropriate interface.
//
g_Log.Write(
LOG_TRACE,
"Activating %s '%S'",
*pfJob ? "job" : "queue",
wszFileName);
if (*pfJob)
{
hr = g_pJobScheduler->Activate(
wszFileName,
IID_ITask,
(IUnknown**)(ITask**)&spJob);
}
else
{
hr = g_pJobScheduler->Activate(
wszFileName,
IID_IUnknown,
(IUnknown**)&spQueue);
}
//
// Bail if the activate failed
//
if (FAILED(hr))
{
g_Log.Write(
LOG_FAIL,
"ITaskScheduler::Activate(%S, IID_ITask%s) hr=%#010x",
wszFileName,
*pfJob ? "" : "Queue",
hr);
break;
}
//
// Replace the passed in job or queue object with the new one.
//
if (*pfJob)
{
if (*ppJob)
{
hr = SaveIfDirty(*ppJob);
(*ppJob)->Release();
}
spJob.Transfer(ppJob);
}
else
{
if (*ppQueue)
{
hr = SaveIfDirty(*ppQueue);
(*ppQueue)->Release();
}
#ifdef NOT_YET
spQueue.Transfer(ppQueue);
#endif // NOT_YET
hr = E_NOTIMPL;
}
}
while (0);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: GetAndPrepareEnumeratorSlot
//
// Synopsis: Get an enumerator slot number from the command line.
//
// Arguments: [ppwsz] - command line
// [pidxSlot] - filled with slot number 0..NUM_ENUMERATOR_SLOTS-1
//
// Returns: S_OK - *[pidxSlot] is valid
// E_INVALIDARG - command line specified bad slot number
//
// Modifies: *pidxSlot
//
// History: 01-30-96 DavidMun Created
//
//----------------------------------------------------------------------------
HRESULT GetEnumeratorSlot(WCHAR **ppwsz, ULONG *pidxSlot)
{
HRESULT hr = S_OK;
do
{
hr = Expect(TKN_NUMBER, ppwsz, L"enumerator slot number");
BREAK_ON_FAILURE(hr);
if (g_ulLastNumberToken >= NUM_ENUMERATOR_SLOTS)
{
hr = E_INVALIDARG;
g_Log.Write(
LOG_ERROR,
"got %u for enumerator slot, but value must be in 0..%u",
g_ulLastNumberToken,
NUM_ENUMERATOR_SLOTS - 1);
break;
}
*pidxSlot = g_ulLastNumberToken;
}
while (0);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: GetAndPrepareEnumeratorSlot
//
// Synopsis: Get an enumerator slot number from the command line, and
// release any existing enumerator at that slot.
//
// Arguments: [ppwsz] - command line
// [pidxSlot] - filled with slot number 0..NUM_ENUMERATOR_SLOTS-1
//
// Returns: S_OK - *[pidxSlot] is valid
// E_INVALIDARG - command line specified bad slot number
//
// Modifies: *pidxSlot, g_apEnumJob[*pidxSlot]
//
// History: 01-30-96 DavidMun Created
//
//----------------------------------------------------------------------------
HRESULT GetAndPrepareEnumeratorSlot(WCHAR **ppwsz, ULONG *pidxSlot)
{
HRESULT hr = S_OK;
do
{
hr = GetEnumeratorSlot(ppwsz, pidxSlot);
BREAK_ON_FAILURE(hr);
//
// If there's an existing enumerator, get rid of it.
//
if (g_apEnumJobs[*pidxSlot])
{
g_Log.Write(
LOG_TRACE,
"Releasing existing enumerator in slot %u",
*pidxSlot);
g_apEnumJobs[*pidxSlot]->Release();
g_apEnumJobs[*pidxSlot] = NULL;
}
}
while (0);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: VerifySlotFilled
//
// Synopsis: Return S_OK if g_apEnumJob[idxSlot] contains a non-NULL
// pointer, E_INVALIDARG otherwise.
//
// History: 01-30-96 DavidMun Created
//
//----------------------------------------------------------------------------
HRESULT VerifySlotFilled(ULONG idxSlot)
{
if (!g_apEnumJobs[idxSlot])
{
g_Log.Write(
LOG_ERROR,
"Slot %u does not contain an enumerator",
idxSlot);
return E_INVALIDARG;
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Function: AddSeconds
//
// Synopsis: Add [ulSeconds] to [pst].
//
// Arguments: [pst] - valid systemtime
// [ulSeconds] - seconds to add
//
// Modifies: *[pst]
//
// History: 04-11-96 DavidMun Created
//
//----------------------------------------------------------------------------
VOID AddSeconds(SYSTEMTIME *pst, ULONG ulSeconds)
{
FILETIME ft;
LONGLONG llTime;
LONGLONG llIncrement;
//
// Convert caller's SYSTEMTIME to a FILETIME, which is easy to do math on.
//
SystemTimeToFileTime(pst, &ft);
//
// Convert the ulSeconds increment from seconds to 100 ns intervals, which
// is the unit used in the FILETIME struct.
//
llIncrement = ulSeconds;
llIncrement *= 10000000UL;
//
// Convert the FILETIME equivalent of pst into a LONGLONG, then add the
// increment.
//
llTime = ft.dwHighDateTime;
llTime <<= 32;
llTime |= ft.dwLowDateTime;
llTime += llIncrement;
//
// Convert the incremented LONGLONG back to a filetime, then convert that
// back to a SYSTEMTIME
//
ft.dwLowDateTime = (DWORD) llTime;
ft.dwHighDateTime = (DWORD) (llTime >> 32);
FileTimeToSystemTime(&ft, pst);
}