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.

1752 lines
43 KiB

  1. //____________________________________________________________________________
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995 - 1996.
  5. //
  6. // File: jobidl.cxx
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // Notes: For the first release of the scheduling agent, all security
  15. // operations are disabled under Win95, even Win95 to NT.
  16. //
  17. // History: 1/24/1996 RaviR Created
  18. //
  19. //____________________________________________________________________________
  20. #include "..\pch\headers.hxx"
  21. #pragma hdrstop
  22. #include "dbg.h"
  23. #include "macros.h"
  24. #include "..\inc\resource.h"
  25. #include "resource.h"
  26. #include "..\wizard\resource.h"
  27. #include "..\inc\common.hxx"
  28. #include "jobidl.hxx"
  29. #include "sch_cls.hxx" // sched\inc
  30. #include "job_cls.hxx" // sched\inc
  31. #include "misc.hxx" // sched\inc
  32. #include "util.hxx"
  33. #include "..\schedui\schedui.hxx"
  34. void
  35. SecurityErrorDialog(
  36. HWND hWndOwner,
  37. HRESULT hr);
  38. /////////////////////////////////////////////////////////////////////////////
  39. /////////////////////////////////////////////////////////////////////////////
  40. ////////
  41. //////// CJobID class implementation
  42. ////////
  43. /////////////////////////////////////////////////////////////////////////////
  44. /////////////////////////////////////////////////////////////////////////////
  45. //+--------------------------------------------------------------------------
  46. //
  47. // Member: CJobID::InitToTemplate
  48. //
  49. // Synopsis: Inititialize this to represent a template object in the
  50. // folder.
  51. //
  52. // History: 05-15-1997 DavidMun Created
  53. //
  54. //---------------------------------------------------------------------------
  55. void
  56. CJobID::InitToTemplate()
  57. {
  58. _id = ID_TEMPLATE;
  59. //
  60. // Name offset is at 1 so the first char can serve to make empty app
  61. // name, creator, and path strings.
  62. //
  63. _oCreator = 0;
  64. _oPath = 0;
  65. _oName = 1;
  66. LoadString(g_hInstance,
  67. IDS_TEMPLATE_NAME,
  68. &_cBuf[_oName],
  69. IDJOB_BUFFER_SIZE - 3);
  70. _cb = offsetof(CJobID, _cBuf) +
  71. (_oName + lstrlen(&_cBuf[_oName]) + 1) * sizeof(TCHAR);
  72. // ^^^ pidl size has to include offset into _cBuf
  73. _NullTerminate();
  74. }
  75. //____________________________________________________________________________
  76. //
  77. // Member: CJobID::Load
  78. //
  79. // Arguments: [pszFolderPath] -- IN
  80. // [pszJob] -- IN
  81. //
  82. // Returns: HRESULT.
  83. //____________________________________________________________________________
  84. HRESULT
  85. CJobID::Load(
  86. LPCTSTR pszFolderPath,
  87. LPTSTR pszJob) // job path relative to Jobs folder with .job extension
  88. {
  89. DEBUG_OUT((DEB_USER12,
  90. "[CJobID::Load] <%ws, %ws>\n",
  91. pszFolderPath ? (LPWSTR)pszFolderPath : L"NULL FolderPath",
  92. pszJob));
  93. #if DBG==1
  94. TCHAR * pExt = PathFindExtension(pszJob);
  95. Win4Assert(lstrcmpi(pExt, TSZ_DOTJOB) == 0);
  96. #endif
  97. HRESULT hr = S_OK;
  98. CJob *pJob = NULL;
  99. SecureZeroMemory(this, sizeof(CJobID));
  100. do
  101. {
  102. //
  103. // Set creation & last write times
  104. //
  105. WCHAR tcFile[MAX_PATH+1];
  106. LPTSTR pFile = tcFile;
  107. if (pszFolderPath != NULL)
  108. {
  109. StringCchCopy(tcFile, MAX_PATH+1, pszFolderPath);
  110. StringCchCat(tcFile, MAX_PATH+1, TEXT("\\"));
  111. StringCchCat(tcFile, MAX_PATH+1, pszJob);
  112. }
  113. else
  114. {
  115. pFile = pszJob;
  116. }
  117. //
  118. // Skip hidden jobs.
  119. //
  120. if (GetFileAttributes(pFile) & FILE_ATTRIBUTE_HIDDEN)
  121. {
  122. return S_FALSE;
  123. }
  124. HANDLE hFile = NULL;
  125. HRESULT hr = OpenFileWithRetry(pFile, GENERIC_READ, FILE_SHARE_READ, &hFile);
  126. if (FAILED(hr))
  127. {
  128. break;
  129. }
  130. if (GetFileTime(hFile, &_ftCreation, NULL, &_ftLastWrite) == FALSE)
  131. {
  132. CloseHandle(hFile);
  133. DEBUG_OUT_LASTERROR;
  134. hr = HRESULT_FROM_WIN32(GetLastError());
  135. break;
  136. }
  137. CloseHandle(hFile);
  138. //
  139. // Create & load the job
  140. //
  141. hr = ::JFCreateAndLoadCJob(pszFolderPath, pszJob, &pJob);
  142. CHECK_HRESULT(hr);
  143. BREAK_ON_FAIL(hr);
  144. _id = ID_JOB;
  145. ////////////////////////////////////////////////////////////
  146. //
  147. // Extract the properties
  148. //
  149. //
  150. // Get last exit code
  151. //
  152. // The return value from this call is the task's last start error.
  153. //
  154. HRESULT hrLastStart = pJob->GetExitCode(&_dwExitCode);
  155. //
  156. // Get a code to tell what to display in the "Status" column.
  157. // For the purposes of this column the job can be:
  158. // a. missed
  159. // b. failed to start
  160. // c. running
  161. // d. other
  162. //
  163. ULONG ulAllFlags;
  164. pJob->GetAllFlags(&ulAllFlags);
  165. if (ulAllFlags & JOB_I_FLAG_MISSED)
  166. {
  167. _status = ejsMissed;
  168. }
  169. else if (FAILED(hrLastStart))
  170. {
  171. switch(hrLastStart)
  172. {
  173. case HRESULT_FROM_WIN32(ERROR_LOGON_FAILURE):
  174. _status = ejsBadAcct;
  175. break;
  176. case HRESULT_FROM_WIN32(ERROR_ACCOUNT_RESTRICTION):
  177. _status = ejsResAcct;
  178. break;
  179. default:
  180. _status = ejsWouldNotStart;
  181. }
  182. }
  183. else
  184. {
  185. HRESULT hrStatus = 0;
  186. hr = pJob->GetStatus(&hrStatus);
  187. CHECK_HRESULT(hr);
  188. BREAK_ON_FAIL(hr);
  189. switch (hrStatus)
  190. {
  191. case SCHED_S_TASK_RUNNING:
  192. _status = ejsRunning;
  193. break;
  194. case SCHED_S_TASK_NOT_SCHEDULED:
  195. _status = ejsNotScheduled;
  196. break;
  197. }
  198. }
  199. //
  200. // Get last run time
  201. //
  202. hr = pJob->GetMostRecentRunTime(&_stLastRunTime);
  203. CHECK_HRESULT(hr);
  204. BREAK_ON_FAIL(hr);
  205. // ensure wDayOfWeek is 0, else memcmp fails.
  206. _stLastRunTime.wDayOfWeek = 0;
  207. //
  208. // Get next run time
  209. //
  210. hr = pJob->GetNextRunTime(&_stNextRunTime);
  211. CHECK_HRESULT(hr);
  212. BREAK_ON_FAIL(hr);
  213. // ensure wDayOfWeek is 0, else memcmp fails.
  214. _stNextRunTime.wDayOfWeek = 0;
  215. //
  216. // Get the job flags
  217. //
  218. hr = pJob->GetFlags(&_ulJobFlags);
  219. CHECK_HRESULT(hr);
  220. BREAK_ON_FAIL(hr);
  221. //
  222. // Get the first job trigger if any
  223. //
  224. hr = pJob->GetTriggerCount(&_cTriggers);
  225. CHECK_HRESULT(hr);
  226. BREAK_ON_FAIL(hr);
  227. if (_cTriggers > 0)
  228. {
  229. ITaskTrigger * pIJobTrigger = NULL;
  230. hr = pJob->GetTrigger(0, &pIJobTrigger);
  231. CHECK_HRESULT(hr);
  232. BREAK_ON_FAIL(hr);
  233. _sJobTrigger.cbTriggerSize = sizeof(TASK_TRIGGER);
  234. hr = pIJobTrigger->GetTrigger(&_sJobTrigger);
  235. pIJobTrigger->Release();
  236. CHECK_HRESULT(hr);
  237. BREAK_ON_FAIL(hr);
  238. }
  239. else
  240. {
  241. _sJobTrigger.cbTriggerSize = 0;
  242. }
  243. ///////////////////////////////////////////////////////////////////
  244. //
  245. // Fill up the buffer cBuf
  246. //
  247. USHORT cchCurr = 0;
  248. //
  249. // Get the command
  250. //
  251. LPWSTR pwszCommand = NULL;
  252. hr = pJob->GetApplicationName(&pwszCommand);
  253. CHECK_HRESULT(hr);
  254. BREAK_ON_FAIL(hr);
  255. StringCchCopy(_cBuf, IDJOB_BUFFER_SIZE, pwszCommand);
  256. CoTaskMemFree(pwszCommand);
  257. DEBUG_OUT((DEB_USER12, "Command = %ws\n", _cBuf));
  258. // update size
  259. cchCurr += lstrlen(_cBuf) + 1;
  260. //
  261. // Get the account name
  262. //
  263. _oCreator = cchCurr;
  264. LPWSTR pwszCreator = NULL;
  265. hr = pJob->GetCreator(&pwszCreator);
  266. CHECK_HRESULT(hr);
  267. BREAK_ON_FAIL(hr);
  268. StringCchCopy(&_cBuf[_oCreator], IDJOB_BUFFER_SIZE - _oCreator, pwszCreator);
  269. CoTaskMemFree(pwszCreator);
  270. // update size
  271. cchCurr += lstrlen(&_cBuf[_oCreator]) + 1;
  272. //
  273. // Copy the job path
  274. //
  275. _oPath = cchCurr;
  276. if (pszFolderPath == NULL)
  277. {
  278. pszJob = PathFindFileName(pszJob);
  279. }
  280. StringCchCopy(&_cBuf[_oPath], IDJOB_BUFFER_SIZE - _oPath, pszJob);
  281. TCHAR * ptcPath = &_cBuf[_oPath];
  282. TCHAR * ptcName = PathFindFileName(ptcPath);
  283. TCHAR * ptcExtn = PathFindExtension(ptcName);
  284. if (ptcExtn)
  285. {
  286. *ptcExtn = TEXT('\0');
  287. }
  288. _oName = _oPath + (USHORT)(ptcName - ptcPath) * sizeof(TCHAR);
  289. // update buff size
  290. cchCurr += lstrlen(ptcPath) + 1;
  291. //
  292. // Finaly set the size
  293. //
  294. _cb = offsetof(CJobID, _cBuf) + cchCurr * sizeof(TCHAR);
  295. //
  296. // Ensure that the DWORD at the end is zero, used by ILClone, etc.
  297. //
  298. _NullTerminate();
  299. } while (0);
  300. if (pJob != NULL)
  301. {
  302. pJob->Release();
  303. }
  304. return hr;
  305. }
  306. //____________________________________________________________________________
  307. //
  308. // Member: CJobID::Rename
  309. //
  310. // Synopsis: Loads this object with data from jidIn, except for
  311. // the name which is set to lpszName.
  312. //
  313. // Arguments: [jidIn] -- IN
  314. // [lpszName] -- IN
  315. //
  316. // Returns: HRESULT.
  317. //
  318. // History: 1/25/1996 RaviR Created
  319. //
  320. //____________________________________________________________________________
  321. HRESULT
  322. CJobID::Rename(
  323. CJobID & jidIn,
  324. LPCOLESTR lpszNameIn)
  325. {
  326. SecureZeroMemory(this, sizeof(CJobID));
  327. CopyMemory(this, &jidIn, jidIn.GetSize());
  328. LPTSTR lpszName = (LPTSTR)lpszNameIn;
  329. StringCchCopy(&_cBuf[_oName], IDJOB_BUFFER_SIZE - _oName, lpszName);
  330. _cb = offsetof(CJobID, _cBuf) +
  331. (_oName + lstrlen(lpszName) + 1) * sizeof(TCHAR);
  332. _NullTerminate();
  333. return S_OK;
  334. }
  335. //____________________________________________________________________________
  336. //
  337. // Member: CJobID::Clone
  338. //
  339. // Returns: CJobID *
  340. //____________________________________________________________________________
  341. CJobID *
  342. CJobID::Clone(void)
  343. {
  344. CJobID * pjid = (CJobID *) SHAlloc(_cb + sizeof(_cb));
  345. if (pjid)
  346. {
  347. CopyMemory(pjid, this, _cb);
  348. pjid->_NullTerminate();
  349. }
  350. return pjid;
  351. }
  352. #if (DBG == 1)
  353. //+--------------------------------------------------------------------------
  354. //
  355. // Member: CJobID::Validate
  356. //
  357. // Synopsis: Assert if this job idlist object is invalid
  358. //
  359. // History: 12-04-1997 DavidMun Created
  360. //
  361. // Notes: For debugging only.
  362. //
  363. //---------------------------------------------------------------------------
  364. VOID
  365. CJobID::Validate()
  366. {
  367. //
  368. // Expect _cb to have been set to nonzero value
  369. //
  370. Win4Assert(_cb);
  371. Win4Assert(_cb < sizeof(CJobID));
  372. //
  373. // Expect all jobids to have a name. Offset should be nonzero because
  374. // name is not the first string.
  375. //
  376. Win4Assert(_oName < IDJOB_BUFFER_SIZE);
  377. //
  378. // Expect that name is null terminated before the end of the buffer.
  379. //
  380. Win4Assert(_oName + lstrlen(GetName()) < IDJOB_BUFFER_SIZE);
  381. //
  382. // Expect the jobid itself to be null terminated
  383. //
  384. UNALIGNED USHORT *pusNextCB = (UNALIGNED USHORT *)(((BYTE *)this) + _cb);
  385. Win4Assert(_cb + sizeof(USHORT) <= sizeof(CJobID));
  386. Win4Assert(!*pusNextCB);
  387. }
  388. #endif // (DBG == 1)
  389. BOOL
  390. GetLocaleDateTimeString(
  391. SYSTEMTIME* pst,
  392. DWORD dwDateFlags,
  393. DWORD dwTimeFlags,
  394. TCHAR szBuff[],
  395. int cchBuffLen,
  396. LPSHELLDETAILS lpDetails);
  397. //____________________________________________________________________________
  398. //
  399. // Member: CJobID::GetNextRunTimeString
  400. //
  401. // Synopsis: S
  402. //
  403. // Arguments: [tcBuff] -- IN
  404. // [cchBuff] -- IN
  405. // [fForComparison] -- IN
  406. //
  407. // Returns: HRESULT.
  408. //
  409. // History: 4/25/1996 RaviR Created
  410. //
  411. //____________________________________________________________________________
  412. LPTSTR
  413. CJobID::GetNextRunTimeString(
  414. TCHAR tcBuff[],
  415. UINT cchBuff,
  416. BOOL fForComparison,
  417. LPSHELLDETAILS lpDetails)
  418. {
  419. if (this->IsJobNotScheduled() == TRUE)
  420. {
  421. LoadString(g_hInstance, IDS_NEVER, tcBuff, cchBuff);
  422. }
  423. else if (this->IsJobFlagOn(TASK_FLAG_DISABLED) == TRUE)
  424. {
  425. LoadString(g_hInstance, IDS_DISABLED, tcBuff, cchBuff);
  426. }
  427. else if (this->IsTriggerFlagOn(TASK_TRIGGER_FLAG_DISABLED))
  428. {
  429. LoadString(g_hInstance, IDS_TRIGGER_DISABLED, tcBuff, cchBuff);
  430. }
  431. else if (this->GetTriggerType() == TASK_EVENT_TRIGGER_AT_SYSTEMSTART)
  432. {
  433. LoadString(g_hInstance, IDS_ON_STARTUP, tcBuff, cchBuff);
  434. }
  435. else if (this->GetTriggerType() == TASK_EVENT_TRIGGER_AT_LOGON)
  436. {
  437. LoadString(g_hInstance, IDS_ON_LOGON, tcBuff, cchBuff);
  438. }
  439. else if (this->GetTriggerType() == TASK_EVENT_TRIGGER_ON_IDLE)
  440. {
  441. LoadString(g_hInstance, IDS_WHEN_IDLE, tcBuff, cchBuff);
  442. }
  443. else
  444. {
  445. SYSTEMTIME &st = this->GetNextRunTime();
  446. if (st.wYear == 0 || st.wMonth == 0 || st.wDay == 0)
  447. {
  448. LoadString(g_hInstance, IDS_NEVER, tcBuff, cchBuff);
  449. }
  450. else
  451. {
  452. if (fForComparison == TRUE)
  453. {
  454. return NULL;
  455. }
  456. GetLocaleDateTimeString(&st, DATE_SHORTDATE, 0, tcBuff, cchBuff, lpDetails);
  457. }
  458. }
  459. return tcBuff;
  460. }
  461. //____________________________________________________________________________
  462. //
  463. // Function: HDROPFromJobIDList
  464. //
  465. // Synopsis: Create an HDROP for the files in the apjid array.
  466. // Used for CF_HDROP format.
  467. //
  468. // Arguments: [cidl] -- IN
  469. // [apjidl] -- IN
  470. //
  471. // Returns: HDROP
  472. //
  473. // History: 1/31/1996 RaviR Created
  474. //
  475. //____________________________________________________________________________
  476. HDROP
  477. HDROPFromJobIDList(
  478. LPCTSTR pszFolderPath,
  479. UINT cidl,
  480. PJOBID * apjidl)
  481. {
  482. HDROP hMem = 0;
  483. LPDROPFILESTRUCT lpDrop;
  484. DWORD dwSize = 0;
  485. if (cidl == 0)
  486. {
  487. return NULL;
  488. }
  489. TCHAR tcFolder[MAX_PATH +1];
  490. StringCchCopy(tcFolder, MAX_PATH +1, pszFolderPath);
  491. StringCchCat(tcFolder, MAX_PATH +1, TEXT("\\"));
  492. USHORT cbFolderPathLen = (USHORT)(lstrlen(tcFolder) * sizeof(TCHAR));
  493. //
  494. // Walk the list and find out how much space we need.
  495. //
  496. dwSize = sizeof(DROPFILESTRUCT) + sizeof(TCHAR); // size + terminal nul
  497. USHORT * pusPathLen = new USHORT[cidl * 2];
  498. if (pusPathLen == NULL)
  499. {
  500. CHECK_HRESULT(E_OUTOFMEMORY);
  501. return NULL;
  502. }
  503. USHORT * pusExtLen = &pusPathLen[cidl];
  504. for (UINT i=0; i < cidl; i++)
  505. {
  506. pusPathLen[i] = (USHORT)(lstrlen(apjidl[i]->GetPath()) * sizeof(TCHAR));
  507. pusExtLen[i] = (USHORT)((lstrlen(apjidl[i]->GetExtension()) + 1) * sizeof(TCHAR));
  508. dwSize += cbFolderPathLen + pusPathLen[i] + pusExtLen[i];
  509. }
  510. //
  511. // If it's bigger than the struct can hold, then bail.
  512. // TODO: Return an error?
  513. //
  514. if (dwSize > 0x0000ffff)
  515. {
  516. delete [] pusPathLen;
  517. return NULL;
  518. }
  519. //
  520. // Allocate the buffer and fill it in.
  521. //
  522. hMem = (HDROP)GlobalAlloc(GHND, dwSize);
  523. if (hMem == NULL)
  524. {
  525. delete [] pusPathLen;
  526. CHECK_HRESULT(E_OUTOFMEMORY);
  527. return NULL;
  528. }
  529. lpDrop = (LPDROPFILESTRUCT) GlobalLock(hMem);
  530. lpDrop->pFiles = (DWORD)(sizeof(DROPFILESTRUCT));
  531. lpDrop->pt.x = 0;
  532. lpDrop->pt.y = 0;
  533. lpDrop->fNC = FALSE;
  534. lpDrop->fWide = TRUE;
  535. //
  536. // Fill in the path names.
  537. //
  538. LPBYTE pbTemp = (LPBYTE) ((LPBYTE) lpDrop + lpDrop->pFiles);
  539. for (i=0; i < cidl; i++)
  540. {
  541. CopyMemory(pbTemp, tcFolder, cbFolderPathLen);
  542. pbTemp += cbFolderPathLen;
  543. CopyMemory(pbTemp, apjidl[i]->GetPath(), pusPathLen[i]);
  544. pbTemp += pusPathLen[i];
  545. CopyMemory(pbTemp, apjidl[i]->GetExtension(), pusExtLen[i]);
  546. pbTemp += pusExtLen[i];
  547. }
  548. *((LPTSTR)pbTemp) = TEXT('\0'); // Extra Nul terminate
  549. //
  550. // Unlock the buffer and return it.
  551. //
  552. GlobalUnlock(hMem);
  553. delete [] pusPathLen;
  554. return hMem;
  555. }
  556. //+--------------------------------------------------------------------------
  557. //
  558. // Function: CreateIDListArray
  559. //
  560. // Synopsis: Create shell idlist array in the format required by the
  561. // CFSTR_SHELLIDLIST clipboard format.
  562. //
  563. // Arguments: [pidlFolder] - pidl of tasks folder
  564. // [cidl] - number of elements in [apjidl]
  565. // [apjidl] - array of pointers to idls, each idl
  566. // specifies a .job object.
  567. //
  568. // Returns: Handle to created array, or NULL on error.
  569. //
  570. // History: 05-30-1997 DavidMun Created
  571. //
  572. // Notes: For this format, the first element in the array is an
  573. // absolute idl to a container (the tasks folder), and the
  574. // remainder (each a single .job object) are relative to the
  575. // first.
  576. //
  577. //---------------------------------------------------------------------------
  578. HGLOBAL
  579. CreateIDListArray(
  580. LPCITEMIDLIST pidlFolder,
  581. UINT cidl,
  582. PJOBID *apjidl)
  583. {
  584. TRACE_FUNCTION(CreateIDListArray);
  585. Win4Assert(cidl);
  586. if (cidl == 0)
  587. {
  588. return NULL;
  589. }
  590. HJOBIDA hJobIDA = NULL;
  591. DWORD offset = sizeof(CJobIDA) + sizeof(UINT) * cidl;
  592. DWORD dwSize = offset;
  593. for (UINT i=0; i < cidl ; i++)
  594. {
  595. dwSize += apjidl[i]->GetSize() + 2; // +2 for null list terminator
  596. }
  597. dwSize += ILGetSize(pidlFolder);
  598. hJobIDA = GlobalAlloc(GPTR, dwSize); // This MUST be GlobalAlloc!!!
  599. if (hJobIDA == NULL)
  600. {
  601. CHECK_HRESULT(E_OUTOFMEMORY);
  602. return NULL;
  603. }
  604. PJOBIDA pJobIDA = (PJOBIDA)hJobIDA; // no need to lock
  605. pJobIDA->cidl = cidl; // count doesn't include idl at offset 0,
  606. pJobIDA->aoffset[0] = offset; // which is container
  607. CopyMemory(((LPBYTE)pJobIDA)+offset, pidlFolder, ILGetSize(pidlFolder));
  608. offset += ILGetSize(pidlFolder);
  609. for (i=0; i < cidl ; i++)
  610. {
  611. UINT cbSize = apjidl[i]->GetSize();
  612. pJobIDA->aoffset[i+1] = offset;
  613. CopyMemory(((LPBYTE)pJobIDA)+offset, apjidl[i], cbSize);
  614. offset += cbSize + 2; // +2 to leave null after copied in idl
  615. }
  616. Win4Assert(offset == dwSize);
  617. return hJobIDA;
  618. }
  619. /////////////////////////////////////////////////////////////////////////////
  620. /////////////////////////////////////////////////////////////////////////////
  621. ////////
  622. //////// CJobIDA related functions.
  623. ////////
  624. /////////////////////////////////////////////////////////////////////////////
  625. /////////////////////////////////////////////////////////////////////////////
  626. //____________________________________________________________________________
  627. //
  628. // Function: HJOBIDA_Create
  629. //
  630. // Synopsis: Create an HJOBIDA for the files in the apjid array.
  631. // Used for CF_JOBIDLIST data format.
  632. //
  633. // Arguments: [cidl] -- IN
  634. // [apjidl] -- IN
  635. //
  636. // Returns: HJOBIDA
  637. //
  638. // History: 1/31/1996 RaviR Created
  639. //
  640. //____________________________________________________________________________
  641. HJOBIDA
  642. HJOBIDA_Create(
  643. UINT cidl,
  644. PJOBID * apjidl)
  645. {
  646. if (cidl == 0)
  647. {
  648. return NULL;
  649. }
  650. HJOBIDA hJobIDA = NULL;
  651. DWORD offset = sizeof(CJobIDA) + sizeof(UINT) * (cidl - 1);
  652. DWORD dwSize = offset;
  653. for (UINT i=0; i < cidl ; i++)
  654. {
  655. dwSize += apjidl[i]->GetSize() + 2; // +2 for null list terminator
  656. }
  657. hJobIDA = GlobalAlloc(GPTR, dwSize); // This MUST be GlobalAlloc with
  658. // GPTR!
  659. if (hJobIDA == NULL)
  660. {
  661. CHECK_HRESULT(E_OUTOFMEMORY);
  662. return NULL;
  663. }
  664. PJOBIDA pJobIDA = (PJOBIDA)hJobIDA; // no need to lock
  665. pJobIDA->cidl = cidl;
  666. //
  667. // Note that apjidl[i] reports its true size, which doesn't include the
  668. // extra 0 ulong following it. That null terminator is required, and
  669. // isn't copied into pJobIDA by the CopyMemory, which is using
  670. // apjidl[i]'s reported size.
  671. //
  672. // Since the GPTR ensures zero-initialized memory, and the extra 2
  673. // bytes per jobid has been accounted for in computing dwSize, we can
  674. // get the terminator just by increasing offset by the terminator size
  675. // on each iteration.
  676. //
  677. for (i=0; i < cidl ; i++)
  678. {
  679. UINT cbSize = apjidl[i]->GetSize();
  680. pJobIDA->aoffset[i] = offset;
  681. CopyMemory(((LPBYTE)pJobIDA)+offset, apjidl[i], cbSize);
  682. offset += cbSize + 2;
  683. }
  684. Win4Assert(offset == dwSize);
  685. return hJobIDA;
  686. }
  687. void
  688. HJOBIDA_Free(
  689. HJOBIDA hJobIDA)
  690. {
  691. GlobalFree(hJobIDA); // This MUST be GlobalFree
  692. }
  693. /////////////////////////////////////////////////////////////////////////////
  694. /////////////////////////////////////////////////////////////////////////////
  695. ////////
  696. //////// Functions to clone and free a LPCITEMIDLIST array.
  697. ////////
  698. /////////////////////////////////////////////////////////////////////////////
  699. /////////////////////////////////////////////////////////////////////////////
  700. //____________________________________________________________________________
  701. //
  702. // Function: ILA_Clone
  703. //
  704. // Synopsis: S
  705. //
  706. // Arguments: [cidl] -- IN
  707. // [apidl] -- IN
  708. //
  709. // Returns: LPITEMIDLIST
  710. //
  711. // History: 1/9/1996 RaviR Created
  712. //
  713. //____________________________________________________________________________
  714. LPITEMIDLIST*
  715. ILA_Clone(
  716. UINT cidl,
  717. LPCITEMIDLIST * apidl)
  718. {
  719. TRACE_FUNCTION(ILA_Clone);
  720. LPITEMIDLIST* aNewPidl = new LPITEMIDLIST[cidl];
  721. if (NULL == aNewPidl)
  722. {
  723. return NULL;
  724. }
  725. for (UINT i = 0; i < cidl; i++)
  726. {
  727. aNewPidl[i] = ILClone(apidl[i]);
  728. if (NULL == aNewPidl[i])
  729. {
  730. // delete what we've allocated so far
  731. for (UINT j = 0; j < i; j++)
  732. {
  733. ILFree(aNewPidl[i]);
  734. }
  735. delete[] aNewPidl;
  736. return NULL;
  737. }
  738. }
  739. return aNewPidl;
  740. }
  741. //____________________________________________________________________________
  742. //
  743. // Function: ILA_Free
  744. //
  745. // Synopsis: S
  746. //
  747. // Arguments: [cidl] -- IN
  748. // [apidl] -- IN
  749. //
  750. // Returns: VOID
  751. //
  752. // History: 1/9/1996 RaviR Created
  753. //
  754. //____________________________________________________________________________
  755. VOID
  756. ILA_Free(
  757. UINT cidl,
  758. LPITEMIDLIST * apidl)
  759. {
  760. TRACE_FUNCTION(ILA_Free);
  761. for (UINT i = 0; i < cidl; i++)
  762. {
  763. ILFree(apidl[i]);
  764. }
  765. delete [] apidl;
  766. }
  767. /////////////////////////////////////////////////////////////////////////////
  768. /////////////////////////////////////////////////////////////////////////////
  769. ////////
  770. //////// Functions to access the CJob & CSchedule
  771. ////////
  772. /////////////////////////////////////////////////////////////////////////////
  773. /////////////////////////////////////////////////////////////////////////////
  774. //____________________________________________________________________________
  775. //
  776. // Function: JFGetJobScheduler
  777. //
  778. // Synopsis: S
  779. //
  780. // Arguments: [ppJobScheduler] -- IN
  781. // [ppwszFolderPath] -- IN
  782. //
  783. // Returns: HRESULT
  784. //
  785. // History: 1/25/1996 RaviR Created
  786. //
  787. //____________________________________________________________________________
  788. HRESULT
  789. JFGetJobScheduler(
  790. LPTSTR pszMachine,
  791. ITaskScheduler ** ppJobScheduler,
  792. LPCTSTR *ppszFolderPath)
  793. {
  794. HRESULT hr = S_OK;
  795. CSchedule * pCSchedule = NULL;
  796. do
  797. {
  798. pCSchedule = new CSchedule;
  799. if (pCSchedule == NULL)
  800. {
  801. hr = E_OUTOFMEMORY;
  802. CHECK_HRESULT(hr);
  803. break;
  804. }
  805. hr = pCSchedule->Init();
  806. CHECK_HRESULT(hr);
  807. BREAK_ON_FAIL(hr);
  808. if (pszMachine != NULL)
  809. {
  810. hr = pCSchedule->SetTargetComputer(pszMachine);
  811. CHECK_HRESULT(hr);
  812. BREAK_ON_FAIL(hr);
  813. }
  814. *ppszFolderPath = pCSchedule->GetFolderPath();
  815. *ppJobScheduler = (ITaskScheduler *)pCSchedule;
  816. } while (0);
  817. if (FAILED(hr) && pCSchedule != NULL)
  818. {
  819. pCSchedule->Release();
  820. }
  821. return hr;
  822. }
  823. //____________________________________________________________________________
  824. //
  825. // Member: CreateAndLoadCJob
  826. //
  827. // Arguments: [pszJob] -- IN
  828. // [ppJob] -- OUT
  829. //
  830. // Returns: HRESULT.
  831. //____________________________________________________________________________
  832. HRESULT
  833. JFCreateAndLoadCJob(
  834. LPCTSTR pszFolderPath,
  835. LPTSTR pszJob, // job path relative to the folder
  836. CJob ** ppJob)
  837. {
  838. TRACE_FUNCTION(CreateAndLoadCJob);
  839. *ppJob = NULL; // init for failure
  840. CJob *pJob = CJob::Create();
  841. if (pJob == NULL)
  842. {
  843. CHECK_HRESULT(E_OUTOFMEMORY);
  844. return E_OUTOFMEMORY;
  845. }
  846. TCHAR buff[MAX_PATH +1];
  847. LPTSTR pszJobPathTemp = pszJob;
  848. if (pszFolderPath != NULL)
  849. {
  850. StringCchCopy(buff, MAX_PATH +1, pszFolderPath);
  851. StringCchCat(buff, MAX_PATH +1, TEXT("\\"));
  852. StringCchCat(buff, MAX_PATH +1, pszJob);
  853. pszJobPathTemp = buff;
  854. }
  855. HRESULT hr = S_OK;
  856. LPWSTR pwszJobPath = pszJobPathTemp;
  857. DEBUG_OUT((DEB_USER1, "Load Job <%ws>\n", pwszJobPath));
  858. hr = pJob->Load(pwszJobPath, STGM_READWRITE | STGM_SHARE_EXCLUSIVE);
  859. if (FAILED(hr))
  860. {
  861. pJob->Release();
  862. CHECK_HRESULT(hr);
  863. return hr;
  864. }
  865. //
  866. // Success, return the object
  867. //
  868. *ppJob = pJob;
  869. return hr;
  870. }
  871. //+--------------------------------------------------------------------------
  872. //
  873. // Function: JFCreateAndLoadTask
  874. //
  875. // Synopsis: Create an in-memory task object and initialize it from
  876. // [pszJob], returning the ITask interface on the object.
  877. //
  878. // Arguments: [pszFolderPath] - path to tasks folder
  879. // [pszJob] - filename of job
  880. // [ppITask] - filled with ITask interface ptr
  881. //
  882. // Returns: HRESULT
  883. //
  884. // Modifies: *[ppITask]
  885. //
  886. // History: 10-07-1997 DavidMun Created
  887. //
  888. // Notes: Caller must Release returned interface.
  889. //
  890. //---------------------------------------------------------------------------
  891. HRESULT
  892. JFCreateAndLoadTask(
  893. LPCTSTR pszFolderPath,
  894. LPTSTR pszJob, // job path relative to the folder
  895. ITask ** ppITask)
  896. {
  897. TRACE_FUNCTION(CreateAndLoadTask);
  898. HRESULT hr;
  899. CJob *pJob;
  900. hr = JFCreateAndLoadCJob(pszFolderPath, pszJob, &pJob);
  901. if (SUCCEEDED(hr))
  902. {
  903. hr = pJob->QueryInterface(IID_ITask, (void **)ppITask);
  904. pJob->Release();
  905. }
  906. return hr;
  907. }
  908. //____________________________________________________________________________
  909. //
  910. // Function: JFSaveJob
  911. //
  912. // Synopsis: Save task settings to storage via the task's IPersistFile
  913. // interface. Also, if applicable, prompt the user for security
  914. // account information.
  915. //
  916. // Arguments: [hwndOwner] -- Owner window.
  917. // [pIJob] -- Target task object.
  918. // [fSecuritySupported] -- Flag indicating if
  919. // security-specific code
  920. // should be invoked.
  921. // [fTaskAccountChange] -- TRUE, the task account
  922. // information has
  923. // changed.
  924. // [fTaskApplicationChange] -- TRUE, the task
  925. // application has
  926. // changed.
  927. // [fSuppressAccountInformationRequest] -- TRUE, do not prompt
  928. // the user for account
  929. // information.
  930. //
  931. // Returns: HRESULT
  932. //
  933. // History: 4/25/1996 RaviR Created
  934. //
  935. //____________________________________________________________________________
  936. HRESULT
  937. JFSaveJob(
  938. HWND hwndOwner,
  939. ITask * pITask,
  940. BOOL fSecuritySupported,
  941. BOOL fTaskAccountChange,
  942. BOOL fTaskApplicationChange,
  943. BOOL fSuppressAccountInformationRequest)
  944. {
  945. AccountInfo AcctInfo;
  946. HRESULT hr;
  947. IPersistFile * pipfTask;
  948. WCHAR * pwszAccountName = NULL;
  949. BOOL fChangesSaved = FALSE;
  950. hr = pITask->QueryInterface(IID_IPersistFile, (void **)&pipfTask);
  951. if (FAILED(hr))
  952. {
  953. return hr;
  954. }
  955. if (fSecuritySupported)
  956. {
  957. InitializeAccountInfo(&AcctInfo);
  958. //
  959. // Application change but no corresponding account information change.
  960. // Launch the set account information dialog in this case.
  961. //
  962. if (fTaskApplicationChange && !fTaskAccountChange)
  963. {
  964. //
  965. // Attempt to retreive account information for the set account
  966. // information dialog. Ignore failures, we would just like to
  967. // have something to fill in the account name control.
  968. //
  969. if (SUCCEEDED(pITask->GetAccountInformation(&pwszAccountName)))
  970. {
  971. AcctInfo.pwszAccountName = pwszAccountName;
  972. }
  973. goto SetAccountInformationDlg;
  974. }
  975. }
  976. //
  977. // Go ahead and save the changes.
  978. //
  979. hr = pipfTask->Save(NULL, FALSE);
  980. fChangesSaved = TRUE;
  981. if (fSecuritySupported)
  982. {
  983. if (FAILED(hr))
  984. {
  985. if (pipfTask->IsDirty() == S_FALSE)
  986. {
  987. //
  988. // If Save failed, yet the job is no longer dirty, the
  989. // error is due to a failure setting security information.
  990. //
  991. // Let the user know there was a problem. Remap the return
  992. // code so we don't get further error dialogs.
  993. //
  994. CHECK_HRESULT(hr);
  995. SecurityErrorDialog(hwndOwner, hr);
  996. hr = S_OK;
  997. }
  998. #if DBG == 1
  999. else
  1000. {
  1001. //
  1002. // Standard persist code failure. Calling page code will
  1003. // put up an error dialog.
  1004. //
  1005. CHECK_HRESULT(hr);
  1006. }
  1007. #endif // DBG == 1
  1008. goto CleanExit;
  1009. }
  1010. if (!fTaskAccountChange)
  1011. {
  1012. //
  1013. // No account information changes. Verify that this job does
  1014. // indeed have account information associated with it.
  1015. //
  1016. hr = pITask->GetAccountInformation(&pwszAccountName);
  1017. if (hr == SCHED_E_ACCOUNT_INFORMATION_NOT_SET)
  1018. {
  1019. //
  1020. // No account information. Launch the set account information
  1021. // dialog.
  1022. //
  1023. hr = S_OK;
  1024. goto SetAccountInformationDlg;
  1025. }
  1026. else if (SUCCEEDED(hr))
  1027. {
  1028. //
  1029. // Done.
  1030. //
  1031. goto CleanExit;
  1032. }
  1033. else
  1034. {
  1035. //
  1036. // In error cases, silently fail. There's nothing we can do
  1037. // about it other than confuse the user. Remapping the return
  1038. // code so the calling page code doesn't put up an error
  1039. // dialog.
  1040. //
  1041. CHECK_HRESULT(hr);
  1042. hr = S_OK;
  1043. goto CleanExit;
  1044. }
  1045. }
  1046. else if (fTaskApplicationChange && fTaskAccountChange)
  1047. {
  1048. //
  1049. // Fetch cached account information from the job object for
  1050. // the pending set account information dialog. Silently fail
  1051. // in an error case.
  1052. //
  1053. hr = pITask->GetAccountInformation(&pwszAccountName);
  1054. Win4Assert(hr != SCHED_E_ACCOUNT_INFORMATION_NOT_SET);
  1055. if (FAILED(hr) || hr == S_FALSE)
  1056. {
  1057. //
  1058. // The information is cached. This would fail for no
  1059. // reason other than insufficient memory.
  1060. //
  1061. // Though, did we goof?
  1062. //
  1063. CHECK_HRESULT(hr);
  1064. hr = S_OK;
  1065. goto CleanExit;
  1066. }
  1067. AcctInfo.pwszAccountName = pwszAccountName;
  1068. }
  1069. else
  1070. {
  1071. //
  1072. // Done.
  1073. //
  1074. goto CleanExit;
  1075. }
  1076. }
  1077. else
  1078. {
  1079. CHECK_HRESULT(hr);
  1080. goto CleanExit;
  1081. }
  1082. SetAccountInformationDlg:
  1083. //
  1084. // Should've arrived here only for security reasons.
  1085. //
  1086. Win4Assert(fSecuritySupported);
  1087. //
  1088. // Can only arrive at this point if the user must specify security
  1089. // account information.
  1090. //
  1091. // Launch the set account information dialog.
  1092. //
  1093. if (!fSuppressAccountInformationRequest)
  1094. {
  1095. LaunchSetAccountInformationDlg(hwndOwner, &AcctInfo);
  1096. //
  1097. // Check if the data is dirty. On dialog entry, the password is set
  1098. // to the global empty string. If the password ptr still equals this,
  1099. // then the user didn't change the password (e.g. the user canceled
  1100. // the dialog).
  1101. //
  1102. if (AcctInfo.pwszAccountName != NULL &&
  1103. AcctInfo.pwszPassword != tszEmpty)
  1104. {
  1105. //
  1106. // Reset the account information and persist the changes.
  1107. //
  1108. hr = pITask->SetAccountInformation(AcctInfo.pwszAccountName,
  1109. AcctInfo.pwszPassword);
  1110. fChangesSaved = FALSE;
  1111. if (FAILED(hr))
  1112. {
  1113. goto CleanExit;
  1114. }
  1115. }
  1116. }
  1117. if (!fChangesSaved)
  1118. {
  1119. CWaitCursor WaitCursor;
  1120. hr = pipfTask->Save(NULL, FALSE);
  1121. if (FAILED(hr) && pipfTask->IsDirty() == S_FALSE)
  1122. {
  1123. //
  1124. // Similar check as above. General save succeeded but the attempt
  1125. // to set security information failed. Let the user know there
  1126. // was a problem and remap the return code so we don't get
  1127. // further dialogs.
  1128. //
  1129. SecurityErrorDialog(hwndOwner, hr);
  1130. hr = S_OK;
  1131. }
  1132. #if DBG == 1
  1133. else
  1134. {
  1135. CHECK_HRESULT(hr);
  1136. }
  1137. #endif // DBG == 1
  1138. }
  1139. CleanExit:
  1140. pipfTask->Release();
  1141. if (fSecuritySupported)
  1142. {
  1143. ResetAccountInfo(&AcctInfo);
  1144. }
  1145. return hr;
  1146. }
  1147. //____________________________________________________________________________
  1148. //
  1149. // Function: SecurityErrorDialog
  1150. //
  1151. // Synopsis: Map the error to a hopefully friendly & informative dialog.
  1152. //
  1153. // Arguments: [hWndOwner] -- Parent window handle.
  1154. // [hr] -- Security error to map.
  1155. //
  1156. // Returns: None.
  1157. //
  1158. // Notes: None.
  1159. //
  1160. //____________________________________________________________________________
  1161. void
  1162. SecurityErrorDialog(
  1163. HWND hWndOwner,
  1164. HRESULT hr)
  1165. {
  1166. int idsErrorMessage;
  1167. UINT idsHelpHint;
  1168. idsErrorMessage = IERR_SECURITY_WRITE_ERROR;
  1169. if (hr == SCHED_E_ACCOUNT_NAME_NOT_FOUND)
  1170. {
  1171. idsHelpHint = IDS_HELP_HINT_INVALID_ACCT;
  1172. }
  1173. else if (hr == SCHED_E_ACCOUNT_DBASE_CORRUPT)
  1174. {
  1175. idsHelpHint = IDS_HELP_HINT_DBASE_CORRUPT;
  1176. }
  1177. else if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED))
  1178. {
  1179. idsHelpHint = IDS_HELP_HINT_ACCESS_DENIED;
  1180. }
  1181. else if (hr == SCHED_E_SERVICE_NOT_RUNNING ||
  1182. HRESULT_FACILITY(hr) == FACILITY_RPC)
  1183. {
  1184. idsHelpHint = IDS_HELP_HINT_SEC_GENERAL;
  1185. }
  1186. else
  1187. {
  1188. //
  1189. // No help hint for unexpected errors.
  1190. //
  1191. idsHelpHint = 0;
  1192. }
  1193. //
  1194. // Put up the error dialog.
  1195. //
  1196. SchedUIErrorDialog(hWndOwner, idsErrorMessage, hr, idsHelpHint);
  1197. }
  1198. //____________________________________________________________________________
  1199. //
  1200. // Function: JFGetAppNameForTask
  1201. //
  1202. // Synopsis: S
  1203. //
  1204. // Arguments: [path] -- IN
  1205. // [pszAppName] -- IN
  1206. // [cchAppName] -- IN
  1207. //
  1208. // Returns: HRESULT
  1209. //
  1210. // History: 4/25/1996 RaviR Created
  1211. //
  1212. //____________________________________________________________________________
  1213. HRESULT
  1214. JFGetAppNameForTask(
  1215. LPCTSTR pszTask, // Full path
  1216. LPTSTR pszAppName,
  1217. UINT cchAppName)
  1218. {
  1219. TRACE_FUNCTION(JFGetAppNameForTask);
  1220. HRESULT hr = S_OK;
  1221. CJob *pJob = CJob::Create();
  1222. if (pJob == NULL)
  1223. {
  1224. CHECK_HRESULT(E_OUTOFMEMORY);
  1225. return E_OUTOFMEMORY;
  1226. }
  1227. hr = pJob->LoadP(pszTask, 0, FALSE, FALSE);
  1228. CHECK_HRESULT(hr);
  1229. if (SUCCEEDED(hr))
  1230. {
  1231. LPWSTR pwszCommand = NULL;
  1232. hr = pJob->GetApplicationName(&pwszCommand);
  1233. CHECK_HRESULT(hr);
  1234. if (SUCCEEDED(hr))
  1235. {
  1236. StringCchCopy(pszAppName, cchAppName, pwszCommand);
  1237. DEBUG_OUT((DEB_USER1, "JFGetAppNameForTask -> %ws\n", pszAppName));
  1238. CoTaskMemFree(pwszCommand);
  1239. }
  1240. }
  1241. pJob->Release();
  1242. return hr;
  1243. }
  1244. BOOL
  1245. IsAScheduleObject(
  1246. TCHAR szFile[])
  1247. {
  1248. if( NULL == szFile )
  1249. {
  1250. return FALSE;
  1251. }
  1252. LPTSTR pszName = PathFindFileName(szFile);
  1253. LPTSTR pszExt = PathFindExtension(pszName);
  1254. if (lstrcmpi(pszExt, TSZ_DOTJOB) != 0)
  1255. // && (lstrcmpi(pszExt, g_szDotQue) != 0)
  1256. {
  1257. return FALSE;
  1258. }
  1259. return TRUE;
  1260. }
  1261. //____________________________________________________________________________
  1262. //
  1263. // Function: JFCopyJob
  1264. //
  1265. // Synopsis: S
  1266. //
  1267. // Arguments: [hwndOwner] -- IN
  1268. // [szFileFrom] -- IN
  1269. // [pszFolderPath] -- IN
  1270. // [fMove] -- IN
  1271. //
  1272. // Returns: HRESULT
  1273. //
  1274. // History: 2/2/1996 RaviR Created
  1275. //
  1276. //____________________________________________________________________________
  1277. HRESULT
  1278. JFCopyJob(
  1279. HWND hwndOwner,
  1280. TCHAR szFileFrom[],
  1281. LPCTSTR pszFolderPath,
  1282. BOOL fMove)
  1283. {
  1284. HRESULT hr = S_OK;
  1285. ITask * pJob = NULL;
  1286. LPTSTR pszName = PathFindFileName(szFileFrom);
  1287. hr = JFCreateAndLoadTask(NULL, szFileFrom, &pJob);
  1288. if (FAILED(hr))
  1289. {
  1290. if (hr == HRESULT_FROM_WIN32(ERROR_INVALID_DATA))
  1291. {
  1292. SchedUIErrorDialog(hwndOwner, IERR_INVALID_DATA, pszName);
  1293. }
  1294. return hr;
  1295. }
  1296. else
  1297. {
  1298. pJob->Release();
  1299. }
  1300. TCHAR szFileTo[MAX_PATH+1];
  1301. StringCchCopy(szFileTo, MAX_PATH +1, pszFolderPath);
  1302. SHFILEOPSTRUCT fo = {hwndOwner, (fMove ? FO_MOVE : FO_COPY), szFileFrom,
  1303. szFileTo, FOF_ALLOWUNDO, FALSE, NULL, NULL};
  1304. // Make sure we have double trailing NULL!
  1305. *(szFileFrom + lstrlen(szFileFrom) + 1) = TEXT('\0');
  1306. if ((SHFileOperation(&fo) !=0) || fo.fAnyOperationsAborted == TRUE)
  1307. {
  1308. hr = E_FAIL;
  1309. CHECK_HRESULT(hr);
  1310. return hr;
  1311. }
  1312. //SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATH, szFileFrom, szFileTo);
  1313. return hr;
  1314. }
  1315. //____________________________________________________________________________
  1316. //
  1317. // Function: GetTriggerStringFromTrigger
  1318. //
  1319. // Synopsis: S
  1320. //
  1321. // Arguments: [pJobTrigger] -- IN
  1322. // [psTrigger] -- IN
  1323. // [cchTrigger] -- IN
  1324. //
  1325. // Returns: HRESULT
  1326. //____________________________________________________________________________
  1327. HRESULT
  1328. GetTriggerStringFromTrigger(
  1329. TASK_TRIGGER * pJobTrigger,
  1330. LPTSTR psTrigger,
  1331. UINT cchTrigger,
  1332. LPSHELLDETAILS lpDetails)
  1333. {
  1334. HRESULT hr = S_OK;
  1335. LPWSTR pwsz = NULL;
  1336. if (pJobTrigger->cbTriggerSize > 0)
  1337. {
  1338. hr = ::StringFromTrigger(pJobTrigger, &pwsz, lpDetails);
  1339. CHECK_HRESULT(hr);
  1340. if (SUCCEEDED(hr))
  1341. {
  1342. if (pwsz)
  1343. {
  1344. StringCchCopy(psTrigger, cchTrigger, pwsz);
  1345. CoTaskMemFree(pwsz);
  1346. }
  1347. else
  1348. return E_FAIL;
  1349. }
  1350. }
  1351. else
  1352. {
  1353. LoadString(g_hInstance, IDS_JOB_NOT_SCHEDULED, psTrigger, cchTrigger);
  1354. }
  1355. return hr;
  1356. }
  1357. /////////////////////////////////////////////////////////////////////////////
  1358. /////////////////////////////////////////////////////////////////////////////
  1359. ////////
  1360. //////// Misc functions.
  1361. ////////
  1362. /////////////////////////////////////////////////////////////////////////////
  1363. /////////////////////////////////////////////////////////////////////////////
  1364. LPITEMIDLIST *
  1365. SHIDLFromJobIDL(
  1366. UINT cidl,
  1367. PJOBID * apjidl)
  1368. {
  1369. LPITEMIDLIST * apidlOut = (LPITEMIDLIST *)SHAlloc(
  1370. sizeof(LPITEMIDLIST) * cidl);
  1371. if (apidlOut)
  1372. {
  1373. for (UINT i=0; i < cidl; i++)
  1374. {
  1375. apidlOut[i] = ILCreateFromPath(apjidl[i]->GetPath());
  1376. if (apidlOut[i] == NULL)
  1377. {
  1378. break;
  1379. }
  1380. }
  1381. if (i < cidl) // => memory error
  1382. {
  1383. while (i--)
  1384. {
  1385. ILFree(apidlOut[i]);
  1386. }
  1387. SHFree(apidlOut);
  1388. apidlOut = NULL;
  1389. }
  1390. }
  1391. #if DBG==1
  1392. if (apidlOut == NULL)
  1393. {
  1394. CHECK_HRESULT(E_OUTOFMEMORY);
  1395. }
  1396. #endif
  1397. return apidlOut;
  1398. }