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.
769 lines
22 KiB
769 lines
22 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// Job Scheduler Service
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1996.
|
|
//
|
|
// File: sch_itf.cxx
|
|
//
|
|
// Contents: job scheduler service interface impementation
|
|
//
|
|
// Classes: CSchedule
|
|
//
|
|
// Interfaces: ITaskScheduler
|
|
//
|
|
// History: 08-Sep-95 EricB created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "..\pch\headers.hxx"
|
|
#pragma hdrstop
|
|
#include "Sched.hxx"
|
|
#include "..\inc\misc.hxx"
|
|
#include "..\inc\network.hxx"
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CSchedule::ITaskScheduler::GetTargetComputer, public
|
|
//
|
|
// Synopsis: Returns the name of the machine towards which the interface is
|
|
// currently targetted.
|
|
//
|
|
// Arguments: [ppwszComputer] - the returned buffer with the machine name
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
// Notes: The string is callee allocated and caller freed with
|
|
// CoTaskMemFree.
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CSchedule::GetTargetComputer(LPWSTR * ppwszComputer)
|
|
{
|
|
TRACE(CSchedule, GetTargetComputer);
|
|
|
|
HRESULT hr;
|
|
DWORD cch = SA_MAX_COMPUTERNAME_LENGTH + 1;
|
|
TCHAR tszLocalName[SA_MAX_COMPUTERNAME_LENGTH + 3] = TEXT("\\\\");
|
|
TCHAR * ptszTargetMachine;
|
|
WCHAR * pwszTargetMachine;
|
|
|
|
if (m_ptszTargetMachine)
|
|
{
|
|
ptszTargetMachine = m_ptszTargetMachine;
|
|
cch = lstrlen(ptszTargetMachine) + 1;
|
|
}
|
|
else // A NULL m_ptszTargetMachine means that we are targetted locally
|
|
{
|
|
if (!GetComputerName(tszLocalName + 2, &cch))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
ERR_OUT("GetTargetComputer: GetComputerName", hr);
|
|
return hr;
|
|
}
|
|
|
|
ptszTargetMachine = tszLocalName;
|
|
cch += 3; // 2 for the leading slashes + 1 for the NULL
|
|
}
|
|
|
|
pwszTargetMachine = ptszTargetMachine;
|
|
|
|
*ppwszComputer = (LPWSTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
|
|
|
|
if (*ppwszComputer == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
s_wcscpy(*ppwszComputer, pwszTargetMachine);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CSchedule::ITaskScheduler::SetTargetComputer, public
|
|
//
|
|
// Synopsis: Sets the machine towards which subsequent ITaskScheduler
|
|
// calls will be directed
|
|
//
|
|
// Arguments: [pwszComputer] - the machine name string
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
// Notes: The string is Caller allocated and freed. The machine name
|
|
// must include two leading backslashes.
|
|
// The caller may indicate using the local machine in one of two
|
|
// ways: by setting pwszComputer to NULL or to the UNC name of the
|
|
// local machine.
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CSchedule::SetTargetComputer(LPCWSTR pwszComputer)
|
|
{
|
|
TRACE(CSchedule, SetTargetComputer);
|
|
HRESULT hr;
|
|
DWORD cch;
|
|
BOOL fLocal = FALSE;
|
|
//
|
|
// Parameter validation. A null param means to target the local computer.
|
|
//
|
|
if (!pwszComputer)
|
|
{
|
|
fLocal = TRUE;
|
|
}
|
|
|
|
LPCTSTR tszPassedInName = pwszComputer;
|
|
if (!fLocal)
|
|
{
|
|
//
|
|
// Get the local machine name to compare with that passed in.
|
|
//
|
|
TCHAR tszLocalName[SA_MAX_COMPUTERNAME_LENGTH + 1];
|
|
cch = SA_MAX_COMPUTERNAME_LENGTH + 1;
|
|
if (!GetComputerName(tszLocalName, &cch))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
ERR_OUT("SetTargetComputer: GetComputerName", hr);
|
|
return hr;
|
|
}
|
|
|
|
TCHAR tszFQDN[SA_MAX_COMPUTERNAME_LENGTH + 1];
|
|
cch = SA_MAX_COMPUTERNAME_LENGTH + 1;
|
|
if (!GetComputerNameEx(ComputerNamePhysicalDnsFullyQualified, tszFQDN, &cch))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
ERR_OUT("SetTargetComputer: GetComputerNameEx", hr);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// skip over first two characters ("\\") of tszPassedInName when comparing
|
|
//
|
|
fLocal = (lstrcmpi(tszPassedInName + 2, tszLocalName) == 0) ||
|
|
(lstrcmpi(tszPassedInName + 2, tszFQDN) == 0);
|
|
}
|
|
|
|
//
|
|
// If targeted remotely, get the folder path out of that machine's
|
|
// registry.
|
|
//
|
|
TCHAR tszFolderPath[MAX_PATH];
|
|
if (!fLocal)
|
|
{
|
|
//
|
|
// Open the remote registry.
|
|
//
|
|
long lErr;
|
|
HKEY hRemoteKey, hSchedKey;
|
|
|
|
lErr = RegConnectRegistry(tszPassedInName, HKEY_LOCAL_MACHINE,
|
|
&hRemoteKey);
|
|
if (lErr != ERROR_SUCCESS)
|
|
{
|
|
schDebugOut((DEB_ERROR, "SetTargetComputer: RegConnectRegistry "
|
|
"failed with error %ld\n",
|
|
lErr));
|
|
return(HRESULT_FROM_WIN32(lErr));
|
|
}
|
|
|
|
lErr = RegOpenKeyEx(hRemoteKey, SCH_AGENT_KEY, 0, KEY_READ,
|
|
&hSchedKey);
|
|
if (lErr != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hRemoteKey);
|
|
|
|
if (lErr == ERROR_BADKEY || lErr == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
return SCHED_E_SERVICE_NOT_INSTALLED;
|
|
}
|
|
|
|
schDebugOut((DEB_ERROR, "SetTargetComputer: RegOpenKeyEx "
|
|
"of Scheduler key failed with error %ld\n",
|
|
lErr));
|
|
return HRESULT_FROM_WIN32(lErr);
|
|
}
|
|
//
|
|
// Get the jobs folder location from the remote registry.
|
|
//
|
|
DWORD cb = MAX_PATH * sizeof(TCHAR);
|
|
TCHAR tszRegFolderValue[MAX_PATH];
|
|
lErr = RegQueryValueEx(hSchedKey, SCH_FOLDER_VALUE, NULL, NULL,
|
|
(LPBYTE)tszRegFolderValue, &cb);
|
|
if (lErr != ERROR_SUCCESS)
|
|
{
|
|
// use default if value absent
|
|
lstrcpy(tszRegFolderValue, TEXT("%SystemRoot%\\Tasks"));
|
|
}
|
|
RegCloseKey(hSchedKey);
|
|
|
|
//
|
|
// BUGBUG: temporary code to expand %SystemRoot% or %WinDir%
|
|
// The installer will have to write a full path to the registry 'cause
|
|
// expanding arbitrary environment strings remotely is too much work.
|
|
//
|
|
cch = ARRAY_LEN("%SystemRoot%") - 1;
|
|
if (_tcsncicmp(tszRegFolderValue, TEXT("%SystemRoot%"), cch) != 0)
|
|
{
|
|
cch = ARRAY_LEN("%WinDir%") - 1;
|
|
if (_tcsncicmp(tszRegFolderValue, TEXT("%WinDir%"), cch) != 0)
|
|
{
|
|
cch = 0;
|
|
}
|
|
}
|
|
|
|
if (cch != 0)
|
|
{
|
|
HKEY hCurVerKey;
|
|
lErr = RegOpenKeyEx(hRemoteKey,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
|
|
0, KEY_ALL_ACCESS,
|
|
&hCurVerKey);
|
|
if (lErr != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hRemoteKey);
|
|
schDebugOut((DEB_ERROR, "SetTargetComputer: RegOpenKeyEx "
|
|
"of CurrentVersion key failed with error %ld\n",
|
|
lErr));
|
|
return HRESULT_FROM_WIN32(lErr);
|
|
}
|
|
TCHAR tszSystemRoot[MAX_PATH];
|
|
cb = MAX_PATH * sizeof(TCHAR);
|
|
lErr = RegQueryValueEx(hCurVerKey, TEXT("SystemRoot"), NULL, NULL,
|
|
(LPBYTE)tszSystemRoot, &cb);
|
|
if (lErr != ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hCurVerKey);
|
|
RegCloseKey(hRemoteKey);
|
|
schDebugOut((DEB_ERROR, "SetTargetComputer: RegQueryValueEx "
|
|
"of CurrentVersion key failed with error %ld\n",
|
|
lErr));
|
|
return HRESULT_FROM_WIN32(lErr);
|
|
}
|
|
RegCloseKey(hCurVerKey);
|
|
lstrcpy(tszFolderPath, tszSystemRoot);
|
|
lstrcat(tszFolderPath, tszRegFolderValue + cch);
|
|
}
|
|
else
|
|
{
|
|
lstrcpy(tszFolderPath, tszRegFolderValue);
|
|
}
|
|
//
|
|
// end of temporary code to expand %SystemRoot%
|
|
//
|
|
|
|
RegCloseKey(hRemoteKey);
|
|
|
|
//
|
|
// Check the folder path for being a fully qualified path name where
|
|
// the first char is the drive designator and the second char is a
|
|
// colon.
|
|
//
|
|
if (!s_isDriveLetter(tszFolderPath[0]) || tszFolderPath[1] != TEXT(':'))
|
|
{
|
|
ERR_OUT("SetTargetComputer: registry path", ERROR_BAD_PATHNAME);
|
|
return HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME);
|
|
}
|
|
//
|
|
// The UNC path to the job folder will be the result of concatonating
|
|
// the machine name and the expanded folder path. The drive designator
|
|
// in the folder path will be turned in an administrative share name
|
|
// by replacing the colon with a dollar sign and will look like:
|
|
// \\machine\c$\windir\jobs
|
|
// so that the count below includes the slash trailing the machine name
|
|
// plus the terminating null.
|
|
//
|
|
cch = lstrlen(tszPassedInName) + 1 + lstrlen(tszFolderPath) + 1;
|
|
}
|
|
else // Targetted locally.
|
|
{
|
|
//
|
|
// Use the local path. Include one for the null terminator.
|
|
//
|
|
cch = lstrlen(g_TasksFolderInfo.ptszPath) + 1;
|
|
}
|
|
|
|
//
|
|
// Allocate the ITaskScheduler folder path string buffer.
|
|
//
|
|
TCHAR * ptszPathBuf = new TCHAR[cch];
|
|
if (!ptszPathBuf)
|
|
{
|
|
ERR_OUT("SetTargetComputer: Job folder path buffer allocation",
|
|
E_OUTOFMEMORY);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Allocate the ITaskScheduler machine name string buffer.
|
|
//
|
|
TCHAR * ptszTargetMachine;
|
|
if (!fLocal)
|
|
{
|
|
cch = lstrlen(tszPassedInName) + 1;
|
|
ptszTargetMachine = new TCHAR[cch];
|
|
if (!ptszTargetMachine)
|
|
{
|
|
ERR_OUT("CSchedule::SetTargetComputer", E_OUTOFMEMORY);
|
|
delete ptszPathBuf;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now that all failable operation have completed sucessfully, we can
|
|
// update the machine name and folder path members.
|
|
//
|
|
|
|
if (m_ptszTargetMachine)
|
|
{
|
|
delete m_ptszTargetMachine;
|
|
}
|
|
|
|
if (m_ptszFolderPath)
|
|
{
|
|
delete m_ptszFolderPath;
|
|
}
|
|
|
|
//
|
|
// Save the new machine name.
|
|
//
|
|
|
|
if (fLocal)
|
|
{
|
|
//
|
|
// If we are targetted locally, the machine name member is set to
|
|
// NULL.
|
|
//
|
|
m_ptszTargetMachine = NULL;
|
|
}
|
|
else
|
|
{
|
|
m_ptszTargetMachine = ptszTargetMachine;
|
|
lstrcpy(m_ptszTargetMachine, tszPassedInName);
|
|
}
|
|
|
|
//
|
|
// Save the folder path name.
|
|
//
|
|
|
|
m_ptszFolderPath = ptszPathBuf;
|
|
|
|
if (fLocal)
|
|
{
|
|
lstrcpy(m_ptszFolderPath, g_TasksFolderInfo.ptszPath);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Convert the folder location to an UNC path.
|
|
//
|
|
// Turn the drive designator into the admin share by replacing the
|
|
// colon with the dollar sign.
|
|
//
|
|
tszFolderPath[1] = TEXT('$');
|
|
//
|
|
// Compose the UNC path.
|
|
//
|
|
lstrcpy(m_ptszFolderPath, tszPassedInName);
|
|
lstrcat(m_ptszFolderPath, TEXT("\\"));
|
|
lstrcat(m_ptszFolderPath, tszFolderPath);
|
|
}
|
|
|
|
schDebugOut((DEB_ITRACE,
|
|
"SetTargetComputer: path to sched folder: \"" FMT_TSTR "\"\n",
|
|
m_ptszFolderPath));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CSchedule::ITaskScheduler::Enum, public
|
|
//
|
|
// Synopsis: Returns a job/queue object enumerator.
|
|
//
|
|
// Arguments: [ppEnumJobs] - a place to return a pointer to the enumerator
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CSchedule::Enum(IEnumWorkItems ** ppEnumJobs)
|
|
{
|
|
TRACE(CSchedule, Enum);
|
|
HRESULT hr;
|
|
|
|
CEnumJobs * pEnumJobs = new CEnumJobs;
|
|
if (pEnumJobs == NULL)
|
|
{
|
|
*ppEnumJobs = NULL;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = pEnumJobs->Init(m_ptszFolderPath);
|
|
if (FAILED(hr))
|
|
{
|
|
delete pEnumJobs;
|
|
*ppEnumJobs = NULL;
|
|
}
|
|
|
|
*ppEnumJobs = pEnumJobs;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CSchedule::ITaskScheduler::NewWorkItem, public
|
|
//
|
|
// Synopsis: Create a new job object.
|
|
//
|
|
// Arguments: [pwszJobName] - the name of the new job *REQUIRED*
|
|
// [riid] - the interface desired
|
|
// [ppunk] - a place to return a pointer to the new job object
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
// Notes: ppwszJobName is caller allocated and freed. The CJob::Save
|
|
// method will copy it before returning. The job name must conform
|
|
// to NT file naming conventions but must not include
|
|
// [back]slashes because nesting within the job object folder is
|
|
// not allowed.
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CSchedule::NewWorkItem(LPCWSTR pwszJobName, REFCLSID rclsid,
|
|
REFIID riid, IUnknown ** ppunk)
|
|
{
|
|
TRACE(CSchedule, NewWorkItem);
|
|
|
|
*ppunk = NULL;
|
|
|
|
if (!IsEqualCLSID(rclsid, CLSID_CTask))
|
|
{
|
|
return CLASS_E_CLASSNOTAVAILABLE;
|
|
}
|
|
|
|
TCHAR * ptszFullName;
|
|
HANDLE hFile;
|
|
|
|
HRESULT hr = CheckJobName(pwszJobName, &ptszFullName);
|
|
if (FAILED(hr))
|
|
{
|
|
ERR_OUT("CSchedule::NewWorkItem: CheckJobName", hr);
|
|
return hr;
|
|
}
|
|
|
|
CJob * pJob = CJob::Create();
|
|
if (pJob == NULL)
|
|
{
|
|
delete [] ptszFullName;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Do the QI before the CreateFile so that if the caller asks for a non-
|
|
// supported interface, the failure will not result in disk operations.
|
|
//
|
|
hr = pJob->QueryInterface(riid, (void **)ppunk);
|
|
if (FAILED(hr))
|
|
{
|
|
ERR_OUT("CSchedule::NewWorkItem: QueryInterface(riid)", hr);
|
|
goto CleanExit;
|
|
}
|
|
// the above QI increased the refcount to 2, so set it back to 1
|
|
pJob->Release();
|
|
|
|
//
|
|
// Per the spec for this method, the file must not already exist.
|
|
//
|
|
hFile = CreateFile(ptszFullName,
|
|
0, // desired access: none
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
// share mode: all
|
|
NULL, // security attributes
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
|
|
if (dwErr == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
//
|
|
// This is good. Save the new filename.
|
|
//
|
|
pJob->m_ptszFileName = ptszFullName;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
ERR_OUT("CSchedule::NewWorkItem: CreateFile", hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Opened successfully - the file exists
|
|
//
|
|
CloseHandle(hFile);
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
|
|
ERR_OUT("CSchedule::NewWorkItem", hr);
|
|
}
|
|
|
|
CleanExit:
|
|
|
|
delete [] ptszFullName;
|
|
delete pJob; // on error, completely destroy the job object
|
|
*ppunk = NULL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CSchedule::ITaskScheduler::AddWorkItem, public
|
|
//
|
|
// Synopsis: Saves the job to the job scheduler folder.
|
|
//
|
|
// Arguments: [pwszJobName] - the name of the job *REQUIRED*
|
|
// [pJob] - pointer to the job object
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
// Notes: Same job name conditions as above.
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CSchedule::AddWorkItem(LPCWSTR pwszJobName,
|
|
IScheduledWorkItem * pWorkItem)
|
|
{
|
|
TRACE(CSchedule, AddWorkItem);
|
|
TCHAR * ptszFullName;
|
|
|
|
HRESULT hr = CheckJobName(pwszJobName, &ptszFullName);
|
|
if (FAILED(hr))
|
|
{
|
|
ERR_OUT("CSchedule::AddWorkItem: CheckJobName", hr);
|
|
return hr;
|
|
}
|
|
IPersistFile * pFile;
|
|
|
|
hr = pWorkItem->QueryInterface(IID_IPersistFile, (void **)&pFile);
|
|
if (FAILED(hr))
|
|
{
|
|
ERR_OUT("CSchedule::AddWorkItem: QI(IPersistFile)", hr);
|
|
delete [] ptszFullName;
|
|
return hr;
|
|
}
|
|
|
|
WCHAR * pwszName;
|
|
|
|
#if !defined(UNICODE)
|
|
|
|
int cch = lstrlen(ptszFullName) + 1;
|
|
pwszName = new WCHAR[cch];
|
|
if (!pwszName)
|
|
{
|
|
ERR_OUT("CSchedule::AddWorkItem", E_OUTOFMEMORY);
|
|
pFile->Release();
|
|
delete [] ptszFullName;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, ptszFullName, -1, pwszName, cch);
|
|
|
|
#else
|
|
|
|
pwszName = ptszFullName;
|
|
|
|
#endif
|
|
|
|
hr = pFile->Save(pwszName, TRUE);
|
|
|
|
// Add this if we want nested folders
|
|
//
|
|
// if (hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND))
|
|
// {
|
|
// //
|
|
// // Create folders as needed
|
|
// //
|
|
// hr = CreateFolders(ptszFullName, TRUE);
|
|
// if (FAILED(hr))
|
|
// {
|
|
// ERR_OUT("AddWorkItem: CreateFolders", hr);
|
|
// pFile->Release();
|
|
// delete [] ptszFullName;
|
|
// #if !defined(UNICODE)
|
|
// delete [] pwszName;
|
|
// #endif
|
|
// return hr;
|
|
// }
|
|
// //
|
|
// // Try again
|
|
// //
|
|
// hr = pFile->Save(pwszName, TRUE);
|
|
// }
|
|
|
|
pFile->Release();
|
|
delete [] ptszFullName;
|
|
#if !defined(UNICODE)
|
|
delete [] pwszName;
|
|
#endif
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CSchedule::ITaskScheduler::Delete, public
|
|
//
|
|
// Synopsis: Deletes the job/queue.
|
|
//
|
|
// Arguments: [pwszJobName] - indicates the job/queue to delete
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CSchedule::Delete(LPCWSTR pwszJobName)
|
|
{
|
|
TRACE(CSchedule, Delete);
|
|
HRESULT hr;
|
|
TCHAR * ptszFullName;
|
|
|
|
hr = CheckJobName(pwszJobName, &ptszFullName);
|
|
if (FAILED(hr))
|
|
{
|
|
ERR_OUT("CSchedule::Delete: CheckJobName", hr);
|
|
return hr;
|
|
}
|
|
|
|
if (!DeleteFile(ptszFullName))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
ERR_OUT("CSchedule::Delete: DeleteFile", hr);
|
|
delete ptszFullName;
|
|
return hr;
|
|
}
|
|
delete ptszFullName;
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CSchedule::ITaskScheduler::Activate, public
|
|
//
|
|
// Synopsis: Given a valid name, returns a pointer to the activated job
|
|
// object
|
|
//
|
|
// Arguments: [pwszName] - the name of the job to activate
|
|
// [riid] - the interface to return
|
|
// [ppunk] - a pointer to the job object interface
|
|
//
|
|
// Returns: hresults
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CSchedule::Activate(LPCWSTR pwszName, REFIID riid, IUnknown ** ppunk)
|
|
{
|
|
TRACE(CSchedule, Activate);
|
|
TCHAR * ptszFullName;
|
|
HRESULT hr = CheckJobName(pwszName, &ptszFullName);
|
|
if (FAILED(hr))
|
|
{
|
|
*ppunk = NULL;
|
|
return hr;
|
|
}
|
|
|
|
CJob * pJob;
|
|
|
|
//
|
|
// CJob is a single-use, in-proc handler, so no need to get OLE in the
|
|
// loop here. Use new (called by CJob::Create) instead of CoCreateInstance.
|
|
//
|
|
pJob = CJob::Create();
|
|
if (pJob == NULL)
|
|
{
|
|
*ppunk = NULL;
|
|
delete [] ptszFullName;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = pJob->LoadP(ptszFullName, 0, TRUE, TRUE);
|
|
|
|
delete [] ptszFullName;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
ERR_OUT("CSchedule::Activate, Load", hr);
|
|
*ppunk = NULL;
|
|
pJob->Release(); // on error, completely release the job object
|
|
return hr;
|
|
}
|
|
|
|
hr = pJob->QueryInterface(riid, (void **)ppunk);
|
|
if (FAILED(hr))
|
|
{
|
|
ERR_OUT("CSchedule::Activate: QueryInterface(riid)", hr);
|
|
*ppunk = NULL;
|
|
pJob->Release(); // on error, completely release the job object
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// The above QI increased the refcount to 2, so set it back to 1.
|
|
//
|
|
pJob->Release();
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CSchedule::ITaskScheduler::IsOfType, public
|
|
//
|
|
// Synopsis: Does this object support the desired interface?
|
|
//
|
|
// Arguments: [pwszName] - indicates the object name
|
|
// [riid] - indicates the interface of interest, typically
|
|
// IID_ITask or IID_IScheduledQueue
|
|
//
|
|
// Returns: S_OK if it is, S_FALSE otherwise.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CSchedule::IsOfType(LPCWSTR pwszName, REFIID riid)
|
|
{
|
|
TRACE(CSchedule, IsOfType);
|
|
|
|
// CODEWORK: A heavyweight implementation for now. It could possibly
|
|
// be optimized by doing the QueryInterface before the LoadP, and
|
|
// doing a lightweight LoadP.
|
|
|
|
IUnknown * punk;
|
|
HRESULT hr = Activate(pwszName, riid, &punk);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
punk->Release();
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
if (hr == HRESULT_FROM_WIN32(ERROR_INVALID_DATA) ||
|
|
hr == SCHED_E_UNKNOWN_OBJECT_VERSION ||
|
|
hr == E_NOINTERFACE)
|
|
{
|
|
//
|
|
// These errors mean that the object is definitely not of a
|
|
// type that we support. We translate them to S_FALSE.
|
|
// Other errors could include file-not-found, access-denied,
|
|
// invalid-arg, etc. We return those errors unmodified.
|
|
//
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|