Leaked source code of windows server 2003
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.

874 lines
26 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Job Scheduler Service
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  7. //
  8. // File: sch_itf.cxx
  9. //
  10. // Contents: job scheduler service interface impementation
  11. //
  12. // Classes: CSchedule
  13. //
  14. // Interfaces: ITaskScheduler
  15. //
  16. // History: 08-Sep-95 EricB created
  17. //
  18. //-----------------------------------------------------------------------------
  19. #include "..\pch\headers.hxx"
  20. #pragma hdrstop
  21. #include "Sched.hxx"
  22. #include <FolderSecurity.h>
  23. //+----------------------------------------------------------------------------
  24. //
  25. // Member: CSchedule::ITaskScheduler::GetTargetComputer, public
  26. //
  27. // Synopsis: Returns the name of the machine towards which the interface is
  28. // currently targetted.
  29. //
  30. // Arguments: [ppwszComputer] - the returned buffer with the machine name
  31. //
  32. // Returns: hresults
  33. //
  34. // Notes: The string is callee allocated and caller freed with
  35. // CoTaskMemFree.
  36. //-----------------------------------------------------------------------------
  37. STDMETHODIMP
  38. CSchedule::GetTargetComputer(LPWSTR * ppwszComputer)
  39. {
  40. TRACE(CSchedule, GetTargetComputer);
  41. if (!ppwszComputer)
  42. {
  43. return E_INVALIDARG;
  44. }
  45. HRESULT hr;
  46. DWORD cch = SA_MAX_COMPUTERNAME_LENGTH + 1;
  47. TCHAR tszLocalName[SA_MAX_COMPUTERNAME_LENGTH + 3] = TEXT("\\\\");
  48. TCHAR * ptszTargetMachine;
  49. WCHAR * pwszTargetMachine;
  50. if (m_ptszTargetMachine)
  51. {
  52. ptszTargetMachine = m_ptszTargetMachine;
  53. cch = lstrlen(ptszTargetMachine) + 1;
  54. }
  55. else // A NULL m_ptszTargetMachine means that we are targetted locally
  56. {
  57. if (!GetComputerName(tszLocalName + 2, &cch))
  58. {
  59. hr = HRESULT_FROM_WIN32(GetLastError());
  60. ERR_OUT("GetTargetComputer: GetComputerName", hr);
  61. return hr;
  62. }
  63. ptszTargetMachine = tszLocalName;
  64. cch += 3; // 2 for the leading slashes + 1 for the NULL
  65. }
  66. pwszTargetMachine = ptszTargetMachine;
  67. *ppwszComputer = (LPWSTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
  68. if (*ppwszComputer == NULL)
  69. {
  70. return E_OUTOFMEMORY;
  71. }
  72. if (FAILED(hr = StringCchCopy(*ppwszComputer, cch, pwszTargetMachine)))
  73. {
  74. return hr;
  75. }
  76. return S_OK;
  77. }
  78. //+----------------------------------------------------------------------------
  79. //
  80. // Member: CSchedule::ITaskScheduler::SetTargetComputer, public
  81. //
  82. // Synopsis: Sets the machine towards which subsequent ITaskScheduler
  83. // calls will be directed
  84. //
  85. // Arguments: [pwszComputer] - the machine name string
  86. //
  87. // Returns: hresults
  88. //
  89. // Notes: The string is Caller allocated and freed. The machine name
  90. // must include two leading backslashes.
  91. // The caller may indicate using the local machine in one of two
  92. // ways: by setting pwszComputer to NULL or to the UNC name of the
  93. // local machine.
  94. //-----------------------------------------------------------------------------
  95. STDMETHODIMP
  96. CSchedule::SetTargetComputer(LPCWSTR pwszComputer)
  97. {
  98. TRACE(CSchedule, SetTargetComputer);
  99. HRESULT hr;
  100. DWORD cch;
  101. BOOL fLocal = FALSE;
  102. //
  103. // Parameter validation. A null param means to target the local computer.
  104. //
  105. if (!pwszComputer)
  106. {
  107. fLocal = TRUE;
  108. }
  109. LPCTSTR tszPassedInName = pwszComputer;
  110. if (!fLocal)
  111. {
  112. //
  113. // Get the local machine name to compare with that passed in.
  114. //
  115. TCHAR tszLocalName[SA_MAX_COMPUTERNAME_LENGTH + 1];
  116. cch = SA_MAX_COMPUTERNAME_LENGTH + 1;
  117. if (!GetComputerName(tszLocalName, &cch))
  118. {
  119. hr = HRESULT_FROM_WIN32(GetLastError());
  120. ERR_OUT("SetTargetComputer: GetComputerName", hr);
  121. return hr;
  122. }
  123. TCHAR tszFQDN[SA_MAX_COMPUTERNAME_LENGTH + 1];
  124. cch = SA_MAX_COMPUTERNAME_LENGTH + 1;
  125. if (!GetComputerNameEx(ComputerNamePhysicalDnsFullyQualified, tszFQDN, &cch))
  126. {
  127. hr = HRESULT_FROM_WIN32(GetLastError());
  128. ERR_OUT("SetTargetComputer: GetComputerNameEx", hr);
  129. return hr;
  130. }
  131. //
  132. // skip over first two characters ("\\") of tszPassedInName when comparing
  133. //
  134. fLocal = (lstrcmpi(tszPassedInName + 2, tszLocalName) == 0) ||
  135. (lstrcmpi(tszPassedInName + 2, tszFQDN) == 0);
  136. }
  137. //
  138. // If targeted remotely, get the folder path out of that machine's
  139. // registry.
  140. //
  141. TCHAR tszFolderPath[MAX_PATH + 1];
  142. if (!fLocal)
  143. {
  144. //
  145. // Open the remote registry.
  146. //
  147. long lErr;
  148. HKEY hRemoteKey, hSchedKey;
  149. lErr = RegConnectRegistry(tszPassedInName, HKEY_LOCAL_MACHINE,
  150. &hRemoteKey);
  151. if (lErr != ERROR_SUCCESS)
  152. {
  153. schDebugOut((DEB_ERROR, "SetTargetComputer: RegConnectRegistry "
  154. "failed with error %ld\n",
  155. lErr));
  156. return(HRESULT_FROM_WIN32(lErr));
  157. }
  158. lErr = RegOpenKeyEx(hRemoteKey, SCH_AGENT_KEY, 0, KEY_READ,
  159. &hSchedKey);
  160. if (lErr != ERROR_SUCCESS)
  161. {
  162. RegCloseKey(hRemoteKey);
  163. if (lErr == ERROR_BADKEY || lErr == ERROR_FILE_NOT_FOUND)
  164. {
  165. return SCHED_E_SERVICE_NOT_INSTALLED;
  166. }
  167. schDebugOut((DEB_ERROR, "SetTargetComputer: RegOpenKeyEx "
  168. "of Scheduler key failed with error %ld\n",
  169. lErr));
  170. return HRESULT_FROM_WIN32(lErr);
  171. }
  172. //
  173. // Get the jobs folder location from the remote registry.
  174. //
  175. DWORD cb = (MAX_PATH + 1) * sizeof(TCHAR);
  176. TCHAR tszRegFolderValue[MAX_PATH + 1];
  177. lErr = RegQueryValueEx(hSchedKey, SCH_FOLDER_VALUE, NULL, NULL,
  178. (LPBYTE)tszRegFolderValue, &cb);
  179. if (lErr != ERROR_SUCCESS)
  180. {
  181. // use default if value absent
  182. StringCchCopy(tszRegFolderValue, MAX_PATH + 1, TEXT("%SystemRoot%\\Tasks"));
  183. }
  184. RegCloseKey(hSchedKey);
  185. //
  186. // BUGBUG: temporary code to expand %SystemRoot% or %WinDir%
  187. // The installer will have to write a full path to the registry 'cause
  188. // expanding arbitrary environment strings remotely is too much work.
  189. //
  190. cch = ARRAY_LEN("%SystemRoot%") - 1;
  191. if (_tcsncicmp(tszRegFolderValue, TEXT("%SystemRoot%"), cch) != 0)
  192. {
  193. cch = ARRAY_LEN("%WinDir%") - 1;
  194. if (_tcsncicmp(tszRegFolderValue, TEXT("%WinDir%"), cch) != 0)
  195. {
  196. cch = 0;
  197. }
  198. }
  199. if (cch != 0)
  200. {
  201. HKEY hCurVerKey;
  202. lErr = RegOpenKeyEx(hRemoteKey,
  203. TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
  204. 0, KEY_ALL_ACCESS,
  205. &hCurVerKey);
  206. if (lErr != ERROR_SUCCESS)
  207. {
  208. RegCloseKey(hRemoteKey);
  209. schDebugOut((DEB_ERROR, "SetTargetComputer: RegOpenKeyEx "
  210. "of CurrentVersion key failed with error %ld\n",
  211. lErr));
  212. return HRESULT_FROM_WIN32(lErr);
  213. }
  214. TCHAR tszSystemRoot[MAX_PATH + 1];
  215. cb = (MAX_PATH + 1) * sizeof(TCHAR);
  216. lErr = RegQueryValueEx(hCurVerKey, TEXT("SystemRoot"), NULL, NULL,
  217. (LPBYTE)tszSystemRoot, &cb);
  218. if (lErr != ERROR_SUCCESS)
  219. {
  220. RegCloseKey(hCurVerKey);
  221. RegCloseKey(hRemoteKey);
  222. schDebugOut((DEB_ERROR, "SetTargetComputer: RegQueryValueEx "
  223. "of CurrentVersion key failed with error %ld\n",
  224. lErr));
  225. return HRESULT_FROM_WIN32(lErr);
  226. }
  227. RegCloseKey(hCurVerKey);
  228. StringCchCopy(tszFolderPath, MAX_PATH + 1, tszSystemRoot);
  229. StringCchCat(tszFolderPath, MAX_PATH + 1, tszRegFolderValue + cch);
  230. }
  231. else
  232. {
  233. StringCchCopy(tszFolderPath, MAX_PATH + 1, tszRegFolderValue);
  234. }
  235. //
  236. // end of temporary code to expand %SystemRoot%
  237. //
  238. RegCloseKey(hRemoteKey);
  239. //
  240. // Check the folder path for being a fully qualified path name where
  241. // the first char is the drive designator and the second char is a
  242. // colon.
  243. //
  244. if (!s_isDriveLetter(tszFolderPath[0]) || tszFolderPath[1] != TEXT(':'))
  245. {
  246. ERR_OUT("SetTargetComputer: registry path", ERROR_BAD_PATHNAME);
  247. return HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME);
  248. }
  249. //
  250. // The UNC path to the job folder will be the result of concatonating
  251. // the machine name and the expanded folder path. The drive designator
  252. // in the folder path will be turned in an administrative share name
  253. // by replacing the colon with a dollar sign and will look like:
  254. // \\machine\c$\windir\jobs
  255. // so that the count below includes the slash trailing the machine name
  256. // plus the terminating null.
  257. //
  258. cch = lstrlen(tszPassedInName) + 1 + lstrlen(tszFolderPath) + 1;
  259. }
  260. else // Targetted locally.
  261. {
  262. //
  263. // Use the local path. Include one for the null terminator.
  264. //
  265. cch = lstrlen(g_TasksFolderInfo.ptszPath) + 1;
  266. }
  267. //
  268. // Allocate the ITaskScheduler folder path string buffer.
  269. //
  270. size_t cchPathBuf = cch;
  271. TCHAR * ptszPathBuf = new TCHAR[cchPathBuf];
  272. if (!ptszPathBuf)
  273. {
  274. ERR_OUT("SetTargetComputer: Job folder path buffer allocation",
  275. E_OUTOFMEMORY);
  276. return E_OUTOFMEMORY;
  277. }
  278. //
  279. // Allocate the ITaskScheduler machine name string buffer.
  280. //
  281. size_t cchTargetMachine = 0;
  282. TCHAR * ptszTargetMachine;
  283. if (!fLocal)
  284. {
  285. cchTargetMachine = lstrlen(tszPassedInName) + 1;
  286. ptszTargetMachine = new TCHAR[cchTargetMachine];
  287. if (!ptszTargetMachine)
  288. {
  289. ERR_OUT("CSchedule::SetTargetComputer", E_OUTOFMEMORY);
  290. delete ptszPathBuf;
  291. return E_OUTOFMEMORY;
  292. }
  293. }
  294. //
  295. // Now that all failable operation have completed sucessfully, we can
  296. // update the machine name and folder path members.
  297. //
  298. if (m_ptszTargetMachine)
  299. {
  300. delete m_ptszTargetMachine;
  301. }
  302. if (m_ptszFolderPath)
  303. {
  304. delete m_ptszFolderPath;
  305. }
  306. //
  307. // Save the new machine name.
  308. //
  309. if (fLocal)
  310. {
  311. //
  312. // If we are targetted locally, the machine name member is set to
  313. // NULL.
  314. //
  315. m_ptszTargetMachine = NULL;
  316. }
  317. else
  318. {
  319. m_ptszTargetMachine = ptszTargetMachine;
  320. StringCchCopy(m_ptszTargetMachine, cchTargetMachine, tszPassedInName);
  321. }
  322. //
  323. // Save the folder path name.
  324. //
  325. m_ptszFolderPath = ptszPathBuf;
  326. if (fLocal)
  327. {
  328. StringCchCopy(m_ptszFolderPath, cchPathBuf, g_TasksFolderInfo.ptszPath);
  329. }
  330. else
  331. {
  332. //
  333. // Convert the folder location to an UNC path.
  334. //
  335. // Turn the drive designator into the admin share by replacing the
  336. // colon with the dollar sign.
  337. //
  338. tszFolderPath[1] = TEXT('$');
  339. //
  340. // Compose the UNC path.
  341. //
  342. StringCchCopy(m_ptszFolderPath, cchPathBuf, tszPassedInName);
  343. StringCchCat(m_ptszFolderPath, cchPathBuf, TEXT("\\"));
  344. StringCchCat(m_ptszFolderPath, cchPathBuf, tszFolderPath);
  345. }
  346. // Now that we have the folder name, check for access
  347. // only check in the remote case - access checks remotely don't always work
  348. // due to problems resolving groups local to remote machine
  349. // this is not a problem, access control will be enforced by the file system on the remote machine.
  350. if (fLocal && FAILED(hr = CoFolderAccessCheck(m_ptszFolderPath, FILE_READ_DATA)))
  351. {
  352. // set back to local machine.
  353. delete[] m_ptszTargetMachine;
  354. m_ptszTargetMachine = NULL;
  355. // set back to something resembling a default state
  356. Init();
  357. return hr;
  358. }
  359. schDebugOut((DEB_ITRACE,
  360. "SetTargetComputer: path to sched folder: \"" FMT_TSTR "\"\n",
  361. m_ptszFolderPath));
  362. return S_OK;
  363. }
  364. //+----------------------------------------------------------------------------
  365. //
  366. // Member: CSchedule::ITaskScheduler::EnumInternal, public
  367. // (public member in class for internal use, not public via API)
  368. //
  369. // Synopsis: Returns a job/queue object enumerator.
  370. // only difference between this and the COM version is that
  371. // this function checks access against the thread/process token
  372. // rather than the COM call context
  373. //
  374. // Arguments: [ppEnumJobs] - a place to return a pointer to the enumerator
  375. //
  376. // Returns: hresults
  377. //
  378. //-----------------------------------------------------------------------------
  379. STDMETHODIMP
  380. CSchedule::EnumInternal(IEnumWorkItems ** ppEnumJobs)
  381. {
  382. TRACE(CSchedule, Enum);
  383. HRESULT hr;
  384. // only check in the remote case - access checks remotely don't always work
  385. // due to problems resolving groups local to remote machine
  386. // this is not a problem, access control will be enforced by the file system on the remote machine.
  387. if ((NULL == m_ptszTargetMachine) && FAILED(hr = FolderAccessCheckOnThreadToken(m_ptszFolderPath, FILE_READ_DATA)))
  388. return hr;
  389. CEnumJobs * pEnumJobs = new CEnumJobs;
  390. if (pEnumJobs == NULL)
  391. {
  392. *ppEnumJobs = NULL;
  393. return E_OUTOFMEMORY;
  394. }
  395. hr = pEnumJobs->Init(m_ptszFolderPath);
  396. if (FAILED(hr))
  397. {
  398. delete pEnumJobs;
  399. *ppEnumJobs = NULL;
  400. }
  401. *ppEnumJobs = pEnumJobs;
  402. return hr;
  403. }
  404. //+----------------------------------------------------------------------------
  405. //
  406. // Member: CSchedule::ITaskScheduler::Enum, public
  407. //
  408. // Synopsis: Returns a job/queue object enumerator.
  409. //
  410. // Arguments: [ppEnumJobs] - a place to return a pointer to the enumerator
  411. //
  412. // Returns: hresults
  413. //
  414. //-----------------------------------------------------------------------------
  415. STDMETHODIMP
  416. CSchedule::Enum(IEnumWorkItems ** ppEnumJobs)
  417. {
  418. TRACE(CSchedule, Enum);
  419. HRESULT hr;
  420. // only check in the remote case - access checks remotely don't always work
  421. // due to problems resolving groups local to remote machine
  422. // this is not a problem, access control will be enforced by the file system on the remote machine.
  423. if ((NULL == m_ptszTargetMachine) && FAILED(hr = CoFolderAccessCheck(m_ptszFolderPath, FILE_READ_DATA)))
  424. return hr;
  425. if (!ppEnumJobs)
  426. {
  427. return E_INVALIDARG;
  428. }
  429. CEnumJobs * pEnumJobs = new CEnumJobs;
  430. if (pEnumJobs == NULL)
  431. {
  432. *ppEnumJobs = NULL;
  433. return E_OUTOFMEMORY;
  434. }
  435. hr = pEnumJobs->Init(m_ptszFolderPath);
  436. if (FAILED(hr))
  437. {
  438. delete pEnumJobs;
  439. *ppEnumJobs = NULL;
  440. }
  441. *ppEnumJobs = pEnumJobs;
  442. return hr;
  443. }
  444. //+----------------------------------------------------------------------------
  445. //
  446. // Member: CSchedule::ITaskScheduler::NewWorkItem, public
  447. //
  448. // Synopsis: Create a new job object.
  449. //
  450. // Arguments: [pwszJobName] - the name of the new job *REQUIRED*
  451. // [riid] - the interface desired
  452. // [ppunk] - a place to return a pointer to the new job object
  453. //
  454. // Returns: hresults
  455. //
  456. // Notes: ppwszJobName is caller allocated and freed. The CJob::Save
  457. // method will copy it before returning. The job name must conform
  458. // to NT file naming conventions but must not include
  459. // [back]slashes because nesting within the job object folder is
  460. // not allowed.
  461. //-----------------------------------------------------------------------------
  462. STDMETHODIMP
  463. CSchedule::NewWorkItem(LPCWSTR pwszJobName, REFCLSID rclsid,
  464. REFIID riid, IUnknown ** ppunk)
  465. {
  466. TRACE(CSchedule, NewWorkItem);
  467. HRESULT hr;
  468. // only check in the remote case - access checks remotely don't always work
  469. // due to problems resolving groups local to remote machine
  470. // this is not a problem, access control will be enforced by the file system on the remote machine.
  471. if ((NULL == m_ptszTargetMachine) && FAILED(hr = CoFolderAccessCheck(m_ptszFolderPath, FILE_WRITE_DATA)))
  472. return hr;
  473. if (!pwszJobName)
  474. {
  475. return E_INVALIDARG;
  476. }
  477. if (!ppunk)
  478. {
  479. return E_INVALIDARG;
  480. }
  481. *ppunk = NULL;
  482. if (!IsEqualCLSID(rclsid, CLSID_CTask))
  483. {
  484. return CLASS_E_CLASSNOTAVAILABLE;
  485. }
  486. TCHAR * ptszFullName;
  487. HANDLE hFile;
  488. hr = CheckJobName(pwszJobName, &ptszFullName);
  489. if (FAILED(hr))
  490. {
  491. ERR_OUT("CSchedule::NewWorkItem: CheckJobName", hr);
  492. return hr;
  493. }
  494. CJob * pJob = CJob::Create();
  495. if (pJob == NULL)
  496. {
  497. delete [] ptszFullName;
  498. return E_OUTOFMEMORY;
  499. }
  500. //
  501. // Do the QI before the CreateFile so that if the caller asks for a non-
  502. // supported interface, the failure will not result in disk operations.
  503. //
  504. hr = pJob->QueryInterface(riid, (void **)ppunk);
  505. if (FAILED(hr))
  506. {
  507. ERR_OUT("CSchedule::NewWorkItem: QueryInterface(riid)", hr);
  508. goto CleanExit;
  509. }
  510. // the above QI increased the refcount to 2, so set it back to 1
  511. pJob->Release();
  512. //
  513. // Per the spec for this method, the file must not already exist.
  514. //
  515. hFile = CreateFile(ptszFullName,
  516. 0, // desired access: none
  517. FILE_SHARE_READ | FILE_SHARE_WRITE,
  518. // share mode: all
  519. NULL, // security attributes
  520. OPEN_EXISTING,
  521. 0,
  522. NULL);
  523. if (hFile == INVALID_HANDLE_VALUE)
  524. {
  525. DWORD dwErr = GetLastError();
  526. if (dwErr == ERROR_FILE_NOT_FOUND)
  527. {
  528. //
  529. // This is good. Save the new filename.
  530. //
  531. pJob->m_ptszFileName = ptszFullName;
  532. return S_OK;
  533. }
  534. else
  535. {
  536. hr = HRESULT_FROM_WIN32(dwErr);
  537. ERR_OUT("CSchedule::NewWorkItem: CreateFile", hr);
  538. }
  539. }
  540. else
  541. {
  542. //
  543. // Opened successfully - the file exists
  544. //
  545. CloseHandle(hFile);
  546. hr = HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
  547. ERR_OUT("CSchedule::NewWorkItem", hr);
  548. }
  549. CleanExit:
  550. delete [] ptszFullName;
  551. delete pJob; // on error, completely destroy the job object
  552. *ppunk = NULL;
  553. return hr;
  554. }
  555. //+----------------------------------------------------------------------------
  556. //
  557. // Member: CSchedule::ITaskScheduler::AddWorkItem, public
  558. //
  559. // Synopsis: Saves the job to the job scheduler folder.
  560. //
  561. // Arguments: [pwszJobName] - the name of the job *REQUIRED*
  562. // [pJob] - pointer to the job object
  563. //
  564. // Returns: hresults
  565. //
  566. // Notes: Same job name conditions as above.
  567. //-----------------------------------------------------------------------------
  568. STDMETHODIMP
  569. CSchedule::AddWorkItem(LPCWSTR pwszJobName,
  570. IScheduledWorkItem * pWorkItem)
  571. {
  572. TRACE(CSchedule, AddWorkItem);
  573. HRESULT hr;
  574. // only check in the remote case - access checks remotely don't always work
  575. // due to problems resolving groups local to remote machine
  576. // this is not a problem, access control will be enforced by the file system on the remote machine.
  577. if ((NULL == m_ptszTargetMachine) && FAILED(hr = CoFolderAccessCheck(m_ptszFolderPath, FILE_WRITE_DATA)))
  578. return hr;
  579. if (!pwszJobName)
  580. {
  581. return E_INVALIDARG;
  582. }
  583. if (!pWorkItem)
  584. {
  585. return E_INVALIDARG;
  586. }
  587. TCHAR * ptszFullName;
  588. hr = CheckJobName(pwszJobName, &ptszFullName);
  589. if (FAILED(hr))
  590. {
  591. ERR_OUT("CSchedule::AddWorkItem: CheckJobName", hr);
  592. return hr;
  593. }
  594. IPersistFile * pFile;
  595. hr = pWorkItem->QueryInterface(IID_IPersistFile, (void **)&pFile);
  596. if (FAILED(hr))
  597. {
  598. ERR_OUT("CSchedule::AddWorkItem: QI(IPersistFile)", hr);
  599. delete [] ptszFullName;
  600. return hr;
  601. }
  602. WCHAR * pwszName;
  603. pwszName = ptszFullName;
  604. hr = pFile->Save(pwszName, TRUE);
  605. pFile->Release();
  606. delete [] ptszFullName;
  607. return hr;
  608. }
  609. //+----------------------------------------------------------------------------
  610. //
  611. // Member: CSchedule::ITaskScheduler::Delete, public
  612. //
  613. // Synopsis: Deletes the job/queue.
  614. //
  615. // Arguments: [pwszJobName] - indicates the job/queue to delete
  616. //
  617. // Returns: hresults
  618. //
  619. //-----------------------------------------------------------------------------
  620. STDMETHODIMP
  621. CSchedule::Delete(LPCWSTR pwszJobName)
  622. {
  623. TRACE(CSchedule, Delete);
  624. HRESULT hr;
  625. // Let's not be redundant, here -
  626. // if (FAILED(hr = CoFolderAccessCheck(m_ptszFolderPath, FILE_DELETE_CHILD)))
  627. // return hr;
  628. if (!pwszJobName)
  629. {
  630. return E_INVALIDARG;
  631. }
  632. TCHAR * ptszFullName;
  633. hr = CheckJobName(pwszJobName, &ptszFullName);
  634. if (FAILED(hr))
  635. {
  636. ERR_OUT("CSchedule::Delete: CheckJobName", hr);
  637. return hr;
  638. }
  639. if (!DeleteFile(ptszFullName))
  640. {
  641. hr = HRESULT_FROM_WIN32(GetLastError());
  642. ERR_OUT("CSchedule::Delete: DeleteFile", hr);
  643. delete ptszFullName;
  644. return hr;
  645. }
  646. delete ptszFullName;
  647. return S_OK;
  648. }
  649. //+----------------------------------------------------------------------------
  650. //
  651. // Member: CSchedule::ITaskScheduler::Activate, public
  652. //
  653. // Synopsis: Given a valid name, returns a pointer to the activated job
  654. // object
  655. //
  656. // Arguments: [pwszName] - the name of the job to activate
  657. // [riid] - the interface to return
  658. // [ppunk] - a pointer to the job object interface
  659. //
  660. // Returns: hresults
  661. //
  662. //-----------------------------------------------------------------------------
  663. STDMETHODIMP
  664. CSchedule::Activate(LPCWSTR pwszName, REFIID riid, IUnknown ** ppunk)
  665. {
  666. TRACE(CSchedule, Activate);
  667. if (!pwszName)
  668. {
  669. return E_INVALIDARG;
  670. }
  671. if (!ppunk)
  672. {
  673. return E_INVALIDARG;
  674. }
  675. TCHAR * ptszFullName;
  676. HRESULT hr = CheckJobName(pwszName, &ptszFullName);
  677. if (FAILED(hr))
  678. {
  679. *ppunk = NULL;
  680. return hr;
  681. }
  682. // only check in the remote case - access checks remotely don't always work
  683. // due to problems resolving groups local to remote machine
  684. // this is not a problem, access control will be enforced by the file system on the remote machine.
  685. if ((NULL == m_ptszTargetMachine) && FAILED(hr = CoFolderAccessCheck(ptszFullName, FILE_READ_DATA)))
  686. {
  687. delete[] ptszFullName;
  688. return hr;
  689. }
  690. CJob * pJob;
  691. //
  692. // CJob is a single-use, in-proc handler, so no need to get OLE in the
  693. // loop here. Use new (called by CJob::Create) instead of CoCreateInstance.
  694. //
  695. pJob = CJob::Create();
  696. if (pJob == NULL)
  697. {
  698. *ppunk = NULL;
  699. delete [] ptszFullName;
  700. return E_OUTOFMEMORY;
  701. }
  702. hr = pJob->LoadP(ptszFullName, 0, TRUE, TRUE);
  703. delete [] ptszFullName;
  704. if (FAILED(hr))
  705. {
  706. ERR_OUT("CSchedule::Activate, Load", hr);
  707. *ppunk = NULL;
  708. pJob->Release(); // on error, completely release the job object
  709. return hr;
  710. }
  711. hr = pJob->QueryInterface(riid, (void **)ppunk);
  712. if (FAILED(hr))
  713. {
  714. ERR_OUT("CSchedule::Activate: QueryInterface(riid)", hr);
  715. *ppunk = NULL;
  716. pJob->Release(); // on error, completely release the job object
  717. return hr;
  718. }
  719. //
  720. // The above QI increased the refcount to 2, so set it back to 1.
  721. //
  722. pJob->Release();
  723. return S_OK;
  724. }
  725. //+----------------------------------------------------------------------------
  726. //
  727. // Member: CSchedule::ITaskScheduler::IsOfType, public
  728. //
  729. // Synopsis: Does this object support the desired interface?
  730. //
  731. // Arguments: [pwszName] - indicates the object name
  732. // [riid] - indicates the interface of interest, typically
  733. // IID_ITask or IID_IScheduledQueue
  734. //
  735. // Returns: S_OK if it is, S_FALSE otherwise.
  736. //
  737. //-----------------------------------------------------------------------------
  738. STDMETHODIMP
  739. CSchedule::IsOfType(LPCWSTR pwszName, REFIID riid)
  740. {
  741. TRACE(CSchedule, IsOfType);
  742. // CODEWORK: A heavyweight implementation for now. It could possibly
  743. // be optimized by doing the QueryInterface before the LoadP, and
  744. // doing a lightweight LoadP.
  745. if (!pwszName)
  746. {
  747. return E_INVALIDARG;
  748. }
  749. IUnknown * punk;
  750. HRESULT hr = Activate(pwszName, riid, &punk);
  751. if (SUCCEEDED(hr))
  752. {
  753. punk->Release();
  754. hr = S_OK;
  755. }
  756. else
  757. {
  758. if (hr == HRESULT_FROM_WIN32(ERROR_INVALID_DATA) ||
  759. hr == SCHED_E_UNKNOWN_OBJECT_VERSION ||
  760. hr == E_NOINTERFACE)
  761. {
  762. //
  763. // These errors mean that the object is definitely not of a
  764. // type that we support. We translate them to S_FALSE.
  765. // Other errors could include file-not-found, access-denied,
  766. // invalid-arg, etc. We return those errors unmodified.
  767. //
  768. hr = S_FALSE;
  769. }
  770. }
  771. return hr;
  772. }