mirror of https://github.com/tongzx/nt5src
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.
841 lines
21 KiB
841 lines
21 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
|
|
//
|
|
// Notes: Recursion into subdirs is currently disabled. To reenable,
|
|
// define ENUM_SUBDIRS and recompile.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#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;
|
|
}
|
|
|
|
*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;
|
|
}
|
|
|
|
#if defined(UNICODE)
|
|
|
|
pwszName = ptszName;
|
|
|
|
#else
|
|
|
|
WCHAR wszName[MAX_PATH];
|
|
hr = AnsiToUnicode(wszName, ptszName, MAX_PATH);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
delete ptszName;
|
|
CoTaskMemFree(*rgpwszNames);
|
|
if (pcJobsFetched)
|
|
{
|
|
*pcJobsFetched = 0;
|
|
}
|
|
*rgpwszNames = NULL;
|
|
return hr;
|
|
}
|
|
pwszName = wszName;
|
|
|
|
#endif
|
|
|
|
**rgpwszNames =
|
|
(LPWSTR)CoTaskMemAlloc((wcslen(pwszName) + 1) * sizeof(WCHAR));
|
|
|
|
if (**rgpwszNames == NULL)
|
|
{
|
|
if (pcJobsFetched != NULL)
|
|
{
|
|
*pcJobsFetched = 0;
|
|
}
|
|
CoTaskMemFree(*rgpwszNames);
|
|
*rgpwszNames = NULL;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
wcscpy(**rgpwszNames, 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);
|
|
|
|
#if defined(UNICODE)
|
|
|
|
pwszName = ptszName;
|
|
|
|
#else
|
|
|
|
hr = AnsiToUnicode(wszName, ptszName, MAX_PATH);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
(*rgpwszNames)[i - 1] =
|
|
(LPWSTR)CoTaskMemAlloc((wcslen(pwszName) + 1) * sizeof(WCHAR));
|
|
|
|
if ((*rgpwszNames)[i - 1] == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
wcscpy((*rgpwszNames)[i - 1], 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);
|
|
if (hr == S_FALSE)
|
|
{
|
|
// we're done
|
|
//
|
|
m_fFindOverrun = TRUE;
|
|
return S_FALSE;
|
|
}
|
|
|
|
TCHAR tszFullDirPath[MAX_PATH];
|
|
|
|
lstrcpy(tszFullDirPath, m_ptszFolderPath);
|
|
|
|
#if defined(ENUM_SUBDIRS)
|
|
|
|
//
|
|
// Note that, unless ENUM_SUBDIRS is defined, that m_tszCurDir is
|
|
// always ".", so it can be ignored here.
|
|
//
|
|
lstrcat(tszFullDirPath, TEXT("\\"));
|
|
lstrcat(tszFullDirPath, m_tszCurDir);
|
|
|
|
#endif // ENUM_SUBDIRS
|
|
|
|
lstrcat(tszFullDirPath, 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);
|
|
|
|
#if defined(ENUM_SUBDIRS)
|
|
//
|
|
// special case: the initial DirStack element is "." so that the
|
|
// job scheduler folder is searched first before decending into
|
|
// subdirs - don't add ".\" as a dir to the path
|
|
//
|
|
if (m_tszCurDir[0] == TEXT('.'))
|
|
{
|
|
#endif // ENUM_SUBDIRS
|
|
|
|
*pptszName = new TCHAR[cch + 1];
|
|
if (*pptszName == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
lstrcpy(*pptszName, FindData.cFileName);
|
|
|
|
#if defined(ENUM_SUBDIRS)
|
|
}
|
|
else
|
|
{
|
|
cch += lstrlen(m_tszCurDir) + 1;
|
|
|
|
*pptszName = new TCHAR[cch + 1];
|
|
if (*pptszName == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
lstrcpy(*pptszName, m_tszCurDir);
|
|
lstrcat(*pptszName, TEXT("\\"));
|
|
lstrcat(*pptszName, FindData.cFileName);
|
|
}
|
|
#endif // ENUM_SUBDIRS
|
|
|
|
}
|
|
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;
|
|
|
|
#if defined(ENUM_SUBDIRS)
|
|
if (pFindData->dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
if (pFindData->cFileName[0] != TEXT('.')) // don't push '.' and '..'
|
|
{
|
|
hr = PushDir(pFindData->cFileName);
|
|
if (FAILED(hr))
|
|
{
|
|
ERR_OUT("CheckFound: PushDir", hr);
|
|
return hr;
|
|
}
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
#endif // ENUM_SUBDIRS
|
|
|
|
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;
|
|
}
|
|
lstrcpy(m_pdsHead->tszDir, 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);
|
|
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;
|
|
}
|
|
|
|
m_ptszFolderPath = new TCHAR[lstrlen(ptszFolderPath) + 1];
|
|
if (!m_ptszFolderPath)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
lstrcpy(m_ptszFolderPath, ptszFolderPath);
|
|
|
|
m_pdsHead = new DIRSTACK;
|
|
if (m_pdsHead == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
lstrcpy(m_pdsHead->tszDir, TEXT("."));
|
|
lstrcpy(m_tszJobExt, TEXT(".") TSZ_JOB);
|
|
// lstrcpy(m_tszQueExt, TEXT(".") g_tszQueueExt);
|
|
|
|
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::PushDir, private
|
|
//
|
|
// Synopsis: Pushes a new directory element on the dir stack. The dir stack
|
|
// stores directory path segments that are rooted relative to the
|
|
// jobs directory.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CEnumJobs::PushDir(LPCTSTR ptszDir)
|
|
{
|
|
#if defined(ENUM_SUBDIRS)
|
|
|
|
PDIRSTACK pdsNode = new DIRSTACK;
|
|
if (pdsNode == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// compose relative path
|
|
// special case: the initial DirStack element is "." so that the
|
|
// job scheduler folder is searched first before decending into
|
|
// subdirs - don't add ".\" as a dir to the path
|
|
//
|
|
if (m_tszCurDir[0] == TEXT('.'))
|
|
{
|
|
lstrcpy(pdsNode->tszDir, ptszDir);
|
|
}
|
|
else
|
|
{
|
|
lstrcpy(pdsNode->tszDir, m_tszCurDir);
|
|
lstrcat(pdsNode->tszDir, TEXT("\\"));
|
|
lstrcat(pdsNode->tszDir, ptszDir);
|
|
}
|
|
|
|
pdsNode->pdsNext = m_pdsHead;
|
|
m_pdsHead = pdsNode;
|
|
|
|
#endif // ENUM_SUBDIRS
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumJobs::PopDir, private
|
|
//
|
|
// Synopsis: Pops the head element off of the dir stack.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CEnumJobs::PopDir(LPTSTR ptszDir)
|
|
{
|
|
if (m_pdsHead == NULL)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
lstrcpy(ptszDir, 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 (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
|
|
|