You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
714 lines
19 KiB
714 lines
19 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// Job Scheduler Service
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1996.
|
|
//
|
|
// File: job_enum.cxx
|
|
//
|
|
// Contents: job object enumerator implementation
|
|
//
|
|
// Classes: CEnumJobs
|
|
//
|
|
// Interfaces: IEnumWorkItems
|
|
//
|
|
// History: 13-Sep-95 EricB created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "..\pch\headers.hxx"
|
|
#pragma hdrstop
|
|
#include "Sched.hxx"
|
|
|
|
void FreeStrings(LPWSTR * rgpwszNames, int n);
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::IEnumWorkItems::Next, public
|
|
//
|
|
// Synopsis: Returns the indicated number of job object monikers
|
|
//
|
|
// Arguments: [cJobs] - the number of jobs to return
|
|
// [rgpwszNames] - the array of returned job names
|
|
// [pcJobsFetched] - the actual number of jobs returned; can be
|
|
// less than or equal to cJobs. Can be NULL if
|
|
// cJobs is equal to one.
|
|
//
|
|
// Returns: S_OK - returned requested number of job names
|
|
// S_FALSE - returned less than requested number of names because
|
|
// the end of the enumeration sequence was reached.
|
|
// E_INVALIDARG or E_OUTOFMEMORY - s.b. obvious
|
|
//
|
|
// Notes: Each LPWSTR in the array must be caller freed using
|
|
// CoTaskMemFree and then the array itself must be freed
|
|
// CoTaskMemFree.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CEnumJobs::Next(ULONG cJobs, LPWSTR ** rgpwszNames, ULONG * pcJobsFetched)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (cJobs == 0)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
if (cJobs > 1 && pcJobsFetched == NULL)
|
|
{
|
|
// as required by IEnumX spec.
|
|
//
|
|
return E_INVALIDARG;
|
|
}
|
|
if (!rgpwszNames)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*rgpwszNames = NULL;
|
|
|
|
if (m_fFindOverrun)
|
|
{
|
|
if (pcJobsFetched != NULL)
|
|
{
|
|
*pcJobsFetched = 0;
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
TCHAR * ptszName;
|
|
WCHAR * pwszName;
|
|
|
|
//
|
|
// find the first requested
|
|
//
|
|
hr = GetNext(&ptszName);
|
|
if (hr != S_OK)
|
|
{
|
|
if (pcJobsFetched != NULL)
|
|
{
|
|
*pcJobsFetched = 0;
|
|
}
|
|
*rgpwszNames = NULL;
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// allocate the first job object name string and the pointer to it
|
|
//
|
|
*rgpwszNames = (LPWSTR *)CoTaskMemAlloc(sizeof(LPWSTR *));
|
|
if (*rgpwszNames == NULL)
|
|
{
|
|
if (pcJobsFetched != NULL)
|
|
{
|
|
*pcJobsFetched = 0;
|
|
}
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
pwszName = ptszName;
|
|
size_t cch = wcslen(pwszName) + 1;
|
|
**rgpwszNames = (LPWSTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
|
|
if (**rgpwszNames == NULL)
|
|
{
|
|
if (pcJobsFetched != NULL)
|
|
{
|
|
*pcJobsFetched = 0;
|
|
}
|
|
CoTaskMemFree(*rgpwszNames);
|
|
*rgpwszNames = NULL;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
StringCchCopy(**rgpwszNames, cch, pwszName);
|
|
|
|
delete ptszName;
|
|
|
|
if (cJobs == 1)
|
|
{
|
|
if (pcJobsFetched != NULL)
|
|
{
|
|
*pcJobsFetched = 1;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Note a check at entry guarantees that at this point pcJobsFetched !=
|
|
// NULL.
|
|
//
|
|
|
|
ULONG i = 1;
|
|
|
|
//
|
|
// find the rest requested
|
|
//
|
|
while (++i <= cJobs)
|
|
{
|
|
hr = GetNext(&ptszName);
|
|
if (hr != S_OK)
|
|
{
|
|
//
|
|
// Either hr == S_FALSE and we've completed successfully because
|
|
// there are no more jobs to enumerate, or else hr is a
|
|
// failure code and we must bail.
|
|
//
|
|
|
|
break;
|
|
}
|
|
LPWSTR * rgpwszTmp = *rgpwszNames;
|
|
|
|
*rgpwszNames = (LPWSTR *)CoTaskMemAlloc(sizeof(LPWSTR *) * i);
|
|
|
|
if (*rgpwszNames == NULL)
|
|
{
|
|
*rgpwszNames = rgpwszTmp; // so cleanup will free strings
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
memcpy(*rgpwszNames, rgpwszTmp, sizeof(LPWSTR *) * (i - 1));
|
|
|
|
CoTaskMemFree(rgpwszTmp);
|
|
|
|
pwszName = ptszName;
|
|
cch = wcslen(pwszName) + 1;
|
|
(*rgpwszNames)[i - 1] = (LPWSTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
|
|
if ((*rgpwszNames)[i - 1] == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
StringCchCopy((*rgpwszNames)[i - 1], cch, pwszName);
|
|
|
|
delete ptszName;
|
|
ptszName = NULL;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
FreeStrings(*rgpwszNames, i - 1);
|
|
delete ptszName;
|
|
*pcJobsFetched = 0;
|
|
*rgpwszNames = NULL;
|
|
}
|
|
else
|
|
{
|
|
*pcJobsFetched = --i;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::GetNext, private
|
|
//
|
|
// Synopsis: enumeration helper
|
|
//
|
|
// Arguments: [pptszName] - the job/queue name, relative to the jobs folder
|
|
//
|
|
// Returns: S_OK - found next file
|
|
// S_FALSE - the end of the enumeration sequence was reached.
|
|
// other code - file system or memory error
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CEnumJobs::GetNext(LPTSTR * pptszName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DWORD dwRet = NO_ERROR;
|
|
WIN32_FIND_DATA FindData;
|
|
//
|
|
// loop until either a matching file is found or the search is done
|
|
//
|
|
do
|
|
{
|
|
//
|
|
// if the find handle is invalid, then we need to start a find in the
|
|
// next directory (which may in fact be the first directory)
|
|
//
|
|
if (m_hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
//
|
|
// Note that, unless ENUM_SUBDIRS is defined, PopDir returns the
|
|
// string "." the first time it is called and returns S_FALSE the
|
|
// second time to stop the enumeration.
|
|
//
|
|
hr = PopDir(m_tszCurDir, MAX_PATH + 1);
|
|
if (hr == S_FALSE)
|
|
{
|
|
// we're done
|
|
//
|
|
m_fFindOverrun = TRUE;
|
|
return S_FALSE;
|
|
}
|
|
|
|
TCHAR tszFullDirPath[MAX_PATH + 1];
|
|
|
|
StringCchCopy(tszFullDirPath, MAX_PATH + 1, m_ptszFolderPath);
|
|
StringCchCat(tszFullDirPath, MAX_PATH + 1, TEXT("\\*"));
|
|
|
|
m_hFind = FindFirstFile(tszFullDirPath, &FindData);
|
|
if (m_hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
dwRet = GetLastError();
|
|
if (dwRet == ERROR_FILE_NOT_FOUND)
|
|
{ // no files in the current dir, check the next dir.
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
return HRESULT_FROM_WIN32(dwRet);
|
|
}
|
|
}
|
|
|
|
hr = CheckFound(&FindData);
|
|
if (hr == S_OK)
|
|
{ // match found
|
|
break;
|
|
}
|
|
if (hr != S_FALSE)
|
|
{ // an error condition
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Continue looking at files in the current dir until a job/queue has
|
|
// been found or the dir has been scanned. If the former, break out of
|
|
// both loops. If the latter, break out of the inner loop and then
|
|
// restart the search on the next dir.
|
|
//
|
|
do
|
|
{
|
|
if (!FindNextFile(m_hFind, &FindData))
|
|
{
|
|
dwRet = GetLastError();
|
|
if (dwRet == ERROR_NO_MORE_FILES)
|
|
{
|
|
FindClose(m_hFind);
|
|
m_hFind = INVALID_HANDLE_VALUE;
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
return HRESULT_FROM_WIN32(dwRet);
|
|
}
|
|
}
|
|
|
|
hr = CheckFound(&FindData);
|
|
if (hr == S_OK)
|
|
{ // match found
|
|
break;
|
|
}
|
|
if (hr != S_FALSE)
|
|
{ // an error condition
|
|
return hr;
|
|
}
|
|
} while (hr != S_OK);
|
|
} while (hr != S_OK);
|
|
|
|
if (pptszName != NULL && dwRet == NO_ERROR)
|
|
{
|
|
int cch = lstrlen(FindData.cFileName);
|
|
|
|
*pptszName = new TCHAR[cch + 1];
|
|
if (*pptszName == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
StringCchCopy(*pptszName, cch + 1, FindData.cFileName);
|
|
}
|
|
m_cFound++;
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::CheckFound, private
|
|
//
|
|
// Synopsis: Checks if the found file is a job or queue. If it is a
|
|
// directory, push it onto the dir stack.
|
|
//
|
|
// Returns: S_OK if a job or queue, S_FALSE if not.
|
|
//
|
|
// Notes: The file find functions match on both long and short versions
|
|
// of file names, so all names of the form *.job* will match
|
|
// (a file like foo.jobber will have a short name of foo~1.job).
|
|
// Thus, the returned file names must be checked for an exact
|
|
// extension match.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CEnumJobs::CheckFound(LPWIN32_FIND_DATA pFindData)
|
|
{
|
|
HRESULT hr;
|
|
|
|
TCHAR * ptszExt = _tcsrchr(pFindData->cFileName, TEXT('.'));
|
|
|
|
if (ptszExt)
|
|
{
|
|
if (lstrcmpi(ptszExt, m_tszJobExt) == 0)
|
|
// || lstrcmpi(ptszExt, m_tszQueExt) == 0
|
|
{
|
|
return S_OK;
|
|
}
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::IEnumWorkItems::Skip, public
|
|
//
|
|
// Synopsis: Skips the indicated number of jobs in the enumeration
|
|
//
|
|
// Arguments: [cJobs] - the number of jobs to skip
|
|
//
|
|
// Returns: S_OK - skipped requested number of job names
|
|
// S_FALSE - skipped less than requested number of names because
|
|
// the end of the enumeration sequence was reached.
|
|
// E_INVALIDARG - if cJobs == 0
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CEnumJobs::Skip(ULONG cJobs)
|
|
{
|
|
if (cJobs == 0)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (m_fFindOverrun)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// skip the requested number
|
|
//
|
|
for (ULONG i = 1; i <= cJobs; i++)
|
|
{
|
|
hr = GetNext(NULL);
|
|
if (hr != S_OK)
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::IEnumWorkItems::Reset, public
|
|
//
|
|
// Synopsis: Sets the enumerator back to its original state
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CEnumJobs::Reset(void)
|
|
{
|
|
if (m_hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
FindClose(m_hFind);
|
|
m_hFind = INVALID_HANDLE_VALUE;
|
|
}
|
|
m_fFindOverrun = FALSE;
|
|
m_cFound = 0;
|
|
ClearDirStack();
|
|
m_pdsHead = new DIRSTACK;
|
|
if (m_pdsHead == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
StringCchCopy(m_pdsHead->tszDir, MAX_PATH + 1, TEXT("."));
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::IEnumWorkItems::Clone, public
|
|
//
|
|
// Synopsis: Creates a copy of the enumerator object with the same state
|
|
//
|
|
// Arguments: [ppEnumJobs] - a place to return a pointer to the enum object
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CEnumJobs::Clone(IEnumWorkItems ** ppEnumJobs)
|
|
{
|
|
TRACE(CEnumJobs, Clone);
|
|
|
|
if (!ppEnumJobs)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
CEnumJobs * pEnumJobs = new CEnumJobs;
|
|
if (pEnumJobs == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto ErrCleanup;
|
|
}
|
|
|
|
hr = pEnumJobs->Init(m_ptszFolderPath);
|
|
if (FAILED(hr))
|
|
{
|
|
goto ErrCleanup;
|
|
}
|
|
|
|
if (m_cFound > 0)
|
|
{
|
|
hr = pEnumJobs->Skip(m_cFound);
|
|
if (FAILED(hr))
|
|
{
|
|
goto ErrCleanup;
|
|
}
|
|
}
|
|
|
|
*ppEnumJobs = pEnumJobs;
|
|
|
|
return S_OK;
|
|
|
|
ErrCleanup:
|
|
|
|
delete pEnumJobs;
|
|
*ppEnumJobs = NULL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::Init, protected
|
|
//
|
|
// Synopsis: Initializes the enumeration
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
// Notes: Initialization is not done during construction since the only
|
|
// way to return ctor errors is to throw an exception.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CEnumJobs::Init(TCHAR * ptszFolderPath)
|
|
{
|
|
TRACE(CEnumJobs, Init);
|
|
if (ptszFolderPath == NULL)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
size_t cch = lstrlen(ptszFolderPath) + 1;
|
|
m_ptszFolderPath = new TCHAR[cch];
|
|
if (!m_ptszFolderPath)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
StringCchCopy(m_ptszFolderPath, cch, ptszFolderPath);
|
|
|
|
m_pdsHead = new DIRSTACK;
|
|
if (m_pdsHead == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
StringCchCopy(m_pdsHead->tszDir, MAX_PATH + 1, TEXT("."));
|
|
StringCchCopy(m_tszJobExt, SCH_SMBUF_LEN, TEXT(".") TSZ_JOB);
|
|
|
|
m_fInitialized = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::CEnumJobs
|
|
//
|
|
// Synopsis: constructor
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CEnumJobs::CEnumJobs(void) :
|
|
m_hFind(INVALID_HANDLE_VALUE),
|
|
m_pdsHead(NULL),
|
|
m_ptszFolderPath(NULL),
|
|
m_cFound(0),
|
|
m_fInitialized(FALSE),
|
|
m_fFindOverrun(FALSE),
|
|
m_uRefs(1)
|
|
{
|
|
m_tszCurDir[0] = TEXT('\0');
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::~CEnumJobs
|
|
//
|
|
// Synopsis: destructor
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CEnumJobs::~CEnumJobs(void)
|
|
{
|
|
if (m_hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
FindClose(m_hFind);
|
|
}
|
|
|
|
ClearDirStack();
|
|
|
|
if (m_ptszFolderPath)
|
|
{
|
|
delete m_ptszFolderPath;
|
|
}
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::PopDir, private
|
|
//
|
|
// Synopsis: Pops the head element off of the dir stack.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CEnumJobs::PopDir(LPTSTR ptszDir, size_t cchBuff)
|
|
{
|
|
if (m_pdsHead == NULL)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
StringCchCopy(ptszDir, cchBuff, m_pdsHead->tszDir);
|
|
PDIRSTACK pdsNode = m_pdsHead->pdsNext;
|
|
delete m_pdsHead;
|
|
m_pdsHead = pdsNode;
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::ClearDirStack, private
|
|
//
|
|
// Synopsis: free the stack element memory
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
CEnumJobs::ClearDirStack(void)
|
|
{
|
|
if (m_pdsHead != NULL)
|
|
{
|
|
PDIRSTACK pdsNode, pdsNextNode;
|
|
pdsNode = m_pdsHead;
|
|
do
|
|
{
|
|
pdsNextNode = pdsNode->pdsNext;
|
|
delete pdsNode;
|
|
pdsNode = pdsNextNode;
|
|
} while (pdsNode);
|
|
m_pdsHead = NULL;
|
|
}
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: FreeStrings
|
|
//
|
|
// Synopsis: Frees the strings contained in the array and then the array
|
|
// itself.
|
|
//
|
|
// Arguments: [rgpwszNames] - the array of strings.
|
|
// [n] - the array size.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
FreeStrings(LPWSTR * rgpwszNames, int n)
|
|
{
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
CoTaskMemFree(rgpwszNames[i]);
|
|
}
|
|
CoTaskMemFree(rgpwszNames);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// CEnumJobs IUnknown methods
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::IUnknown::QueryInterface
|
|
//
|
|
// Synopsis: Returns requested interface pointer
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CEnumJobs::QueryInterface(REFIID riid, void ** ppvObject)
|
|
{
|
|
if (!ppvObject)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (IID_IUnknown == riid)
|
|
{
|
|
*ppvObject = (IUnknown *)(IEnumWorkItems *)this;
|
|
}
|
|
else if (IID_IEnumWorkItems == riid)
|
|
{
|
|
*ppvObject = (IUnknown *)(IEnumWorkItems *)this;
|
|
}
|
|
else
|
|
{
|
|
*ppvObject = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::IUnknown::AddRef
|
|
//
|
|
// Synopsis: increments reference count
|
|
//
|
|
// Returns: the reference count
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG)
|
|
CEnumJobs::AddRef(void)
|
|
{
|
|
return InterlockedIncrement((long *)&m_uRefs);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::IUnknown::Release
|
|
//
|
|
// Synopsis: Decrements the object's reference count and frees it when
|
|
// no longer referenced.
|
|
//
|
|
// Returns: zero if the reference count is zero or non-zero otherwise
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG)
|
|
CEnumJobs::Release(void)
|
|
{
|
|
unsigned long uTmp;
|
|
if ((uTmp = InterlockedDecrement((long *)&m_uRefs)) == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return uTmp;
|
|
}
|
|
|
|
// BUGBUG: need a class factory if the interface is going to be exposed to OA
|
|
|